From 8436bfdd7821b006c730ed3d77839ed75c419ac6 Mon Sep 17 00:00:00 2001 From: Mikael Finstad Date: Tue, 14 May 2024 12:13:35 +0200 Subject: [PATCH] implement 2 more configurable seek speeds closes #1994 https://github.com/mifi/lossless-cut/issues/254#issuecomment-1876623395 https://github.com/mifi/lossless-cut/issues/254#issuecomment-589509889 #1611 #1884 --- src/main/configStore.ts | 4 +++ src/renderer/src/App.tsx | 35 +++++++++---------- .../src/components/KeyboardShortcuts.tsx | 20 +++++++++-- src/renderer/src/components/Settings.tsx | 16 ++++++++- src/renderer/src/components/ValueTuner.tsx | 2 +- src/renderer/src/components/ValueTuners.tsx | 22 ++++++++++-- src/renderer/src/hooks/useKeyboard.ts | 2 +- src/renderer/src/hooks/useUserSettingsRoot.ts | 8 +++++ src/renderer/src/types.ts | 2 +- types.ts | 4 ++- 10 files changed, 87 insertions(+), 28 deletions(-) diff --git a/src/main/configStore.ts b/src/main/configStore.ts index 76e24a53..babe4080 100644 --- a/src/main/configStore.ts +++ b/src/main/configStore.ts @@ -32,12 +32,14 @@ const defaultKeyBindings: KeyBinding[] = [ { keys: 'g', action: 'goToTimecode' }, { keys: 'left', action: 'seekBackwards' }, + { keys: 'ctrl+shift+left', action: 'seekBackwards2' }, { keys: 'ctrl+left', action: 'seekBackwardsPercent' }, { keys: 'command+left', action: 'seekBackwardsPercent' }, { keys: 'alt+left', action: 'seekBackwardsKeyframe' }, { keys: 'shift+left', action: 'jumpCutStart' }, { keys: 'right', action: 'seekForwards' }, + { keys: 'ctrl+shift+right', action: 'seekForwards2' }, { keys: 'ctrl+right', action: 'seekForwardsPercent' }, { keys: 'command+right', action: 'seekForwardsPercent' }, { keys: 'alt+right', action: 'seekForwardsKeyframe' }, @@ -114,6 +116,8 @@ const defaults: Config = { outSegTemplate: undefined, keyboardSeekAccFactor: 1.03, keyboardNormalSeekSpeed: 1, + keyboardSeekSpeed2: 10, + keyboardSeekSpeed3: 60, treatInputFileModifiedTimeAsStart: true, treatOutputFileModifiedTimeAsStart: true, outFormatLocked: undefined, diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index a7d44b90..2e2fbf40 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -195,7 +195,7 @@ function App() { const allUserSettings = useUserSettingsRoot(); const { - captureFormat, setCaptureFormat, customOutDir, setCustomOutDir, keyframeCut, setKeyframeCut, preserveMovData, setPreserveMovData, movFastStart, setMovFastStart, avoidNegativeTs, autoMerge, timecodeFormat, invertCutSegments, setInvertCutSegments, autoExportExtraStreams, askBeforeClose, enableAskForImportChapters, enableAskForFileOpenAction, playbackVolume, setPlaybackVolume, autoSaveProjectFile, wheelSensitivity, invertTimelineScroll, language, ffmpegExperimental, hideNotifications, autoLoadTimecode, autoDeleteMergedSegments, exportConfirmEnabled, setExportConfirmEnabled, segmentsToChapters, setSegmentsToChapters, preserveMetadataOnMerge, setPreserveMetadataOnMerge, simpleMode, setSimpleMode, outSegTemplate, setOutSegTemplate, keyboardSeekAccFactor, keyboardNormalSeekSpeed, treatInputFileModifiedTimeAsStart, treatOutputFileModifiedTimeAsStart, outFormatLocked, setOutFormatLocked, safeOutputFileName, setSafeOutputFileName, enableAutoHtml5ify, segmentsToChaptersOnly, keyBindings, setKeyBindings, resetKeyBindings, enableSmartCut, customFfPath, storeProjectInWorkingDir, setStoreProjectInWorkingDir, enableOverwriteOutput, mouseWheelZoomModifierKey, captureFrameMethod, captureFrameQuality, captureFrameFileNameFormat, enableNativeHevc, cleanupChoices, setCleanupChoices, darkMode, setDarkMode, preferStrongColors, outputFileNameMinZeroPadding, cutFromAdjustmentFrames, + captureFormat, setCaptureFormat, customOutDir, setCustomOutDir, keyframeCut, setKeyframeCut, preserveMovData, setPreserveMovData, movFastStart, setMovFastStart, avoidNegativeTs, autoMerge, timecodeFormat, invertCutSegments, setInvertCutSegments, autoExportExtraStreams, askBeforeClose, enableAskForImportChapters, enableAskForFileOpenAction, playbackVolume, setPlaybackVolume, autoSaveProjectFile, wheelSensitivity, invertTimelineScroll, language, ffmpegExperimental, hideNotifications, autoLoadTimecode, autoDeleteMergedSegments, exportConfirmEnabled, setExportConfirmEnabled, segmentsToChapters, setSegmentsToChapters, preserveMetadataOnMerge, setPreserveMetadataOnMerge, simpleMode, setSimpleMode, outSegTemplate, setOutSegTemplate, keyboardSeekAccFactor, keyboardNormalSeekSpeed, keyboardSeekSpeed2, keyboardSeekSpeed3, treatInputFileModifiedTimeAsStart, treatOutputFileModifiedTimeAsStart, outFormatLocked, setOutFormatLocked, safeOutputFileName, setSafeOutputFileName, enableAutoHtml5ify, segmentsToChaptersOnly, keyBindings, setKeyBindings, resetKeyBindings, enableSmartCut, customFfPath, storeProjectInWorkingDir, setStoreProjectInWorkingDir, enableOverwriteOutput, mouseWheelZoomModifierKey, captureFrameMethod, captureFrameQuality, captureFrameFileNameFormat, enableNativeHevc, cleanupChoices, setCleanupChoices, darkMode, setDarkMode, preferStrongColors, outputFileNameMinZeroPadding, cutFromAdjustmentFrames, } = allUserSettings; useEffect(() => { @@ -2087,6 +2087,15 @@ function App() { seekAccelerationRef.current = 1; } + function seekRel2({ keyup, amount }: { keyup: boolean | undefined, amount: number }) { + if (keyup) { + seekReset(); + return; + } + seekRel(seekAccelerationRef.current * amount); + seekAccelerationRef.current *= keyboardSeekAccFactor; + } + const ret: Record boolean) | ((a: { keyup?: boolean | undefined }) => void)> = { // NOTE: Do not change these keys because users have bound keys by these names in their config files // For actions, see also KeyboardShortcuts.jsx @@ -2111,22 +2120,12 @@ function App() { splitCurrentSegment, increaseRotation, goToTimecode, - seekBackwards({ keyup }) { - if (keyup) { - seekReset(); - return; - } - seekRel(keyboardNormalSeekSpeed * seekAccelerationRef.current * -1); - seekAccelerationRef.current *= keyboardSeekAccFactor; - }, - seekForwards({ keyup }) { - if (keyup) { - seekReset(); - return; - } - seekRel(keyboardNormalSeekSpeed * seekAccelerationRef.current); - seekAccelerationRef.current *= keyboardSeekAccFactor; - }, + seekBackwards: ({ keyup }) => seekRel2({ keyup, amount: -1 * keyboardNormalSeekSpeed }), + seekBackwards2: ({ keyup }) => seekRel2({ keyup, amount: -1 * keyboardSeekSpeed2 }), + seekBackwards3: ({ keyup }) => seekRel2({ keyup, amount: -1 * keyboardSeekSpeed3 }), + seekForwards: ({ keyup }) => seekRel2({ keyup, amount: keyboardNormalSeekSpeed }), + seekForwards2: ({ keyup }) => seekRel2({ keyup, amount: keyboardSeekSpeed2 }), + seekForwards3: ({ keyup }) => seekRel2({ keyup, amount: keyboardSeekSpeed3 }), seekBackwardsPercent: () => { seekRelPercent(-0.01); return false; }, seekForwardsPercent: () => { seekRelPercent(0.01); return false; }, seekBackwardsKeyframe: () => seekClosestKeyframe(-1), @@ -2220,7 +2219,7 @@ function App() { }; return ret; - }, [addSegment, alignSegmentTimesToKeyframes, apparentCutSegments, askStartTimeOffset, batchFileJump, batchOpenSelectedFile, captureSnapshot, captureSnapshotAsCoverArt, changePlaybackRate, checkFileOpened, cleanupFilesDialog, clearSegments, closeBatch, closeFileWithConfirm, combineOverlappingSegments, combineSelectedSegments, concatBatch, convertFormatBatch, copySegmentsToClipboard, createFixedDurationSegments, createNumSegments, createRandomSegments, createSegmentsFromKeyframes, currentSegIndexSafe, cutSegments.length, cutSegmentsHistory, deselectAllSegments, detectBlackScenes, detectSceneChanges, detectSilentScenes, duplicateCurrentSegment, editCurrentSegmentTags, extractAllStreams, extractCurrentSegmentFramesAsImages, extractSelectedSegmentsFramesAsImages, fillSegmentsGaps, goToTimecode, handleShowStreamsSelectorClick, increaseRotation, invertAllSegments, invertSelectedSegments, jumpCutEnd, jumpCutStart, jumpSeg, jumpTimelineEnd, jumpTimelineStart, keyboardNormalSeekSpeed, keyboardSeekAccFactor, onExportPress, onLabelSegment, openFilesDialog, openSendReportDialogWithState, pause, play, removeCutSegment, removeSelectedSegments, reorderSegsByStartTime, seekClosestKeyframe, seekRel, seekRelPercent, selectAllSegments, selectOnlyCurrentSegment, setCurrentSegIndex, setCutEnd, setCutStart, setPlaybackVolume, shiftAllSegmentTimes, shortStep, showIncludeExternalStreamsDialog, shuffleSegments, splitCurrentSegment, timelineToggleComfortZoom, toggleCaptureFormat, toggleCurrentSegmentSelected, toggleFullscreenVideo, toggleKeyframeCut, toggleLastCommands, toggleLoopSelectedSegments, togglePlay, toggleSegmentsList, toggleSettings, toggleShowKeyframes, toggleShowThumbnails, toggleStreamsSelector, toggleStripAudio, toggleStripThumbnail, toggleWaveformMode, tryFixInvalidDuration, userHtml5ifyCurrentFile, zoomRel]); + }, [addSegment, alignSegmentTimesToKeyframes, apparentCutSegments, askStartTimeOffset, batchFileJump, batchOpenSelectedFile, captureSnapshot, captureSnapshotAsCoverArt, changePlaybackRate, checkFileOpened, cleanupFilesDialog, clearSegments, closeBatch, closeFileWithConfirm, combineOverlappingSegments, combineSelectedSegments, concatBatch, convertFormatBatch, copySegmentsToClipboard, createFixedDurationSegments, createNumSegments, createRandomSegments, createSegmentsFromKeyframes, currentSegIndexSafe, cutSegments.length, cutSegmentsHistory, deselectAllSegments, detectBlackScenes, detectSceneChanges, detectSilentScenes, duplicateCurrentSegment, editCurrentSegmentTags, extractAllStreams, extractCurrentSegmentFramesAsImages, extractSelectedSegmentsFramesAsImages, fillSegmentsGaps, goToTimecode, handleShowStreamsSelectorClick, increaseRotation, invertAllSegments, invertSelectedSegments, jumpCutEnd, jumpCutStart, jumpSeg, jumpTimelineEnd, jumpTimelineStart, keyboardNormalSeekSpeed, keyboardSeekAccFactor, keyboardSeekSpeed2, keyboardSeekSpeed3, onExportPress, onLabelSegment, openFilesDialog, openSendReportDialogWithState, pause, play, removeCutSegment, removeSelectedSegments, reorderSegsByStartTime, seekClosestKeyframe, seekRel, seekRelPercent, selectAllSegments, selectOnlyCurrentSegment, setCurrentSegIndex, setCutEnd, setCutStart, setPlaybackVolume, shiftAllSegmentTimes, shortStep, showIncludeExternalStreamsDialog, shuffleSegments, splitCurrentSegment, timelineToggleComfortZoom, toggleCaptureFormat, toggleCurrentSegmentSelected, toggleFullscreenVideo, toggleKeyframeCut, toggleLastCommands, toggleLoopSelectedSegments, togglePlay, toggleSegmentsList, toggleSettings, toggleShowKeyframes, toggleShowThumbnails, toggleStreamsSelector, toggleStripAudio, toggleStripThumbnail, toggleWaveformMode, tryFixInvalidDuration, userHtml5ifyCurrentFile, zoomRel]); const getKeyboardAction = useCallback((action: MainKeyboardAction) => mainActions[action], [mainActions]); diff --git a/src/renderer/src/components/KeyboardShortcuts.tsx b/src/renderer/src/components/KeyboardShortcuts.tsx index 0071f9d5..5e0fd902 100644 --- a/src/renderer/src/components/KeyboardShortcuts.tsx +++ b/src/renderer/src/components/KeyboardShortcuts.tsx @@ -224,11 +224,27 @@ const KeyboardShortcuts = memo(({ category: seekingCategory, }, seekBackwards: { - name: t('Seek backward 1 sec'), + name: t('Backward seek'), category: seekingCategory, }, seekForwards: { - name: t('Seek forward 1 sec'), + name: t('Forward seek'), + category: seekingCategory, + }, + seekBackwards2: { + name: t('Backward seek (longer)'), + category: seekingCategory, + }, + seekForwards2: { + name: t('Forward seek (longer)'), + category: seekingCategory, + }, + seekBackwards3: { + name: t('Backward seek (longest)'), + category: seekingCategory, + }, + seekForwards3: { + name: t('Forward seek (longest)'), category: seekingCategory, }, seekBackwardsKeyframe: { diff --git a/src/renderer/src/components/Settings.tsx b/src/renderer/src/components/Settings.tsx index 7532360c..7b46971d 100644 --- a/src/renderer/src/components/Settings.tsx +++ b/src/renderer/src/components/Settings.tsx @@ -357,12 +357,26 @@ const Settings = memo(({ - {t('Timeline keyboard seek speed')} + {t('Timeline keyboard seek interval')} + + {t('Timeline keyboard seek interval (longer)')} + + + + + + + {t('Timeline keyboard seek interval (longest)')} + + + + + {t('Timeline keyboard seek acceleration')} diff --git a/src/renderer/src/components/ValueTuner.tsx b/src/renderer/src/components/ValueTuner.tsx index a7360c3e..ba835bc5 100644 --- a/src/renderer/src/components/ValueTuner.tsx +++ b/src/renderer/src/components/ValueTuner.tsx @@ -35,7 +35,7 @@ const ValueTuner = memo(({ style, title, value, setValue, onFinished, resolution
{title}
-
{value.toFixed(4)}
+
{value.toFixed(4)}
{t('Precise')}
diff --git a/src/renderer/src/components/ValueTuners.tsx b/src/renderer/src/components/ValueTuners.tsx index 36065597..44dca485 100644 --- a/src/renderer/src/components/ValueTuners.tsx +++ b/src/renderer/src/components/ValueTuners.tsx @@ -7,7 +7,7 @@ import { TunerType } from '../types'; const ValueTuners = memo(({ type, onFinished }: { type: TunerType, onFinished: () => void }) => { const { t } = useTranslation(); - const { wheelSensitivity, setWheelSensitivity, keyboardNormalSeekSpeed, setKeyboardNormalSeekSpeed, keyboardSeekAccFactor, setKeyboardSeekAccFactor } = useUserSettings(); + const { wheelSensitivity, setWheelSensitivity, keyboardNormalSeekSpeed, keyboardSeekSpeed2, setKeyboardSeekSpeed2, keyboardSeekSpeed3, setKeyboardSeekSpeed3, setKeyboardNormalSeekSpeed, keyboardSeekAccFactor, setKeyboardSeekAccFactor } = useUserSettings(); // NOTE default values are duplicated in src/main/configStore.js const types = { @@ -20,13 +20,29 @@ const ValueTuners = memo(({ type, onFinished }: { type: TunerType, onFinished: ( default: 0.2, }, keyboardNormalSeekSpeed: { - title: t('Timeline keyboard seek speed'), + title: t('Timeline keyboard seek interval'), value: keyboardNormalSeekSpeed, setValue: setKeyboardNormalSeekSpeed, min: 0, - max: 100, + max: 120, default: 1, }, + keyboardSeekSpeed2: { + title: t('Timeline keyboard seek interval (longer)'), + value: keyboardSeekSpeed2, + setValue: setKeyboardSeekSpeed2, + min: 0, + max: 600, + default: 10, + }, + keyboardSeekSpeed3: { + title: t('Timeline keyboard seek interval (longest)'), + value: keyboardSeekSpeed3, + setValue: setKeyboardSeekSpeed3, + min: 0, + max: 3600, + default: 60, + }, keyboardSeekAccFactor: { title: t('Timeline keyboard seek acceleration'), value: keyboardSeekAccFactor, diff --git a/src/renderer/src/hooks/useKeyboard.ts b/src/renderer/src/hooks/useKeyboard.ts index 3692c34e..02741e01 100644 --- a/src/renderer/src/hooks/useKeyboard.ts +++ b/src/renderer/src/hooks/useKeyboard.ts @@ -9,7 +9,7 @@ import { KeyBinding, KeyboardAction } from '../../../../types'; // for all dialog actions (e.g. detectSceneChanges) we must use keyup, or we risk having the button press inserted into the dialog's input element right after the dialog opens // todo use keyup for most events? -const keyupActions = new Set(['seekBackwards', 'seekForwards', 'detectBlackScenes', 'detectSilentScenes', 'detectSceneChanges']); +const keyupActions = new Set(['seekBackwards', 'seekForwards', 'seekBackwards2', 'seekForwards2', 'seekBackwards3', 'seekForwards3', 'detectBlackScenes', 'detectSilentScenes', 'detectSceneChanges']); interface StoredAction { action: KeyboardAction, keyup?: boolean } diff --git a/src/renderer/src/hooks/useUserSettingsRoot.ts b/src/renderer/src/hooks/useUserSettingsRoot.ts index 94f0f12d..48c15082 100644 --- a/src/renderer/src/hooks/useUserSettingsRoot.ts +++ b/src/renderer/src/hooks/useUserSettingsRoot.ts @@ -99,6 +99,10 @@ export default () => { useEffect(() => safeSetConfig({ keyboardSeekAccFactor }), [keyboardSeekAccFactor]); const [keyboardNormalSeekSpeed, setKeyboardNormalSeekSpeed] = useState(safeGetConfigInitial('keyboardNormalSeekSpeed')); useEffect(() => safeSetConfig({ keyboardNormalSeekSpeed }), [keyboardNormalSeekSpeed]); + const [keyboardSeekSpeed2, setKeyboardSeekSpeed2] = useState(safeGetConfigInitial('keyboardSeekSpeed2')); + useEffect(() => safeSetConfig({ keyboardSeekSpeed2 }), [keyboardSeekSpeed2]); + const [keyboardSeekSpeed3, setKeyboardSeekSpeed3] = useState(safeGetConfigInitial('keyboardSeekSpeed3')); + useEffect(() => safeSetConfig({ keyboardSeekSpeed3 }), [keyboardSeekSpeed3]); const [treatInputFileModifiedTimeAsStart, setTreatInputFileModifiedTimeAsStart] = useState(safeGetConfigInitial('treatInputFileModifiedTimeAsStart')); useEffect(() => safeSetConfig({ treatInputFileModifiedTimeAsStart }), [treatInputFileModifiedTimeAsStart]); @@ -220,6 +224,10 @@ export default () => { setKeyboardSeekAccFactor, keyboardNormalSeekSpeed, setKeyboardNormalSeekSpeed, + keyboardSeekSpeed2, + setKeyboardSeekSpeed2, + keyboardSeekSpeed3, + setKeyboardSeekSpeed3, treatInputFileModifiedTimeAsStart, setTreatInputFileModifiedTimeAsStart, treatOutputFileModifiedTimeAsStart, diff --git a/src/renderer/src/types.ts b/src/renderer/src/types.ts index bd804863..8e43a457 100644 --- a/src/renderer/src/types.ts +++ b/src/renderer/src/types.ts @@ -70,7 +70,7 @@ export type EdlImportType = 'youtube' | EdlFileType; export type EdlExportType = 'csv' | 'tsv-human' | 'csv-human' | 'csv-frames' | 'srt' | 'llc'; -export type TunerType = 'wheelSensitivity' | 'keyboardNormalSeekSpeed' | 'keyboardSeekAccFactor'; +export type TunerType = 'wheelSensitivity' | 'keyboardNormalSeekSpeed' | 'keyboardSeekSpeed2' | 'keyboardSeekSpeed3' | 'keyboardSeekAccFactor'; export interface RenderableWaveform { createdAt: Date, diff --git a/types.ts b/types.ts index 698027f3..40d1af30 100644 --- a/types.ts +++ b/types.ts @@ -1,4 +1,4 @@ -export type KeyboardAction = 'addSegment' | 'togglePlayResetSpeed' | 'togglePlayNoResetSpeed' | 'reducePlaybackRate' | 'reducePlaybackRateMore' | 'increasePlaybackRate' | 'increasePlaybackRateMore' | 'timelineToggleComfortZoom' | 'seekPreviousFrame' | 'seekNextFrame' | 'captureSnapshot' | 'setCutStart' | 'setCutEnd' | 'removeCurrentSegment' | 'cleanupFilesDialog' | 'splitCurrentSegment' | 'increaseRotation' | 'goToTimecode' | 'seekBackwards' | 'seekBackwardsPercent' | 'seekBackwardsPercent' | 'seekBackwardsKeyframe' | 'jumpCutStart' | 'seekForwards' | 'seekForwardsPercent' | 'seekForwardsPercent' | 'seekForwardsKeyframe' | 'jumpCutEnd' | 'jumpTimelineStart' | 'jumpTimelineEnd' | 'jumpFirstSegment' | 'jumpPrevSegment' | 'timelineZoomIn' | 'timelineZoomIn' | 'batchPreviousFile' | 'jumpLastSegment' | 'jumpNextSegment' | 'timelineZoomOut' | 'timelineZoomOut' | 'batchNextFile' | 'batchOpenSelectedFile' | 'batchOpenPreviousFile' | 'batchOpenNextFile' | 'undo' | 'undo' | 'redo' | 'redo' | 'copySegmentsToClipboard' | 'copySegmentsToClipboard' | 'toggleFullscreenVideo' | 'labelCurrentSegment' | 'export' | 'toggleKeyboardShortcuts' | 'closeActiveScreen' | 'increaseVolume' | 'decreaseVolume' | 'detectBlackScenes' | 'detectSilentScenes' | 'detectSceneChanges' | 'toggleLastCommands' | 'play' | 'pause' | 'reloadFile' | 'html5ify' | 'togglePlayOnlyCurrentSegment' | 'toggleLoopOnlyCurrentSegment' | 'toggleLoopStartEndOnlyCurrentSegment' | 'toggleLoopSelectedSegments' | 'editCurrentSegmentTags' | 'duplicateCurrentSegment' | 'reorderSegsByStartTime' | 'invertAllSegments' | 'fillSegmentsGaps' | 'shiftAllSegmentTimes' | 'alignSegmentTimesToKeyframes' | 'createSegmentsFromKeyframes' | 'createFixedDurationSegments' | 'createNumSegments' | 'createRandomSegments' | 'shuffleSegments' | 'combineOverlappingSegments' | 'combineSelectedSegments' | 'clearSegments' | 'toggleSegmentsList' | 'selectOnlyCurrentSegment' | 'deselectAllSegments' | 'selectAllSegments' | 'toggleCurrentSegmentSelected' | 'invertSelectedSegments' | 'removeSelectedSegments' | 'toggleStreamsSelector' | 'extractAllStreams' | 'showStreamsSelector' | 'showIncludeExternalStreamsDialog' | 'captureSnapshotAsCoverArt' | 'extractCurrentSegmentFramesAsImages' | 'extractSelectedSegmentsFramesAsImages' | 'convertFormatBatch' | 'convertFormatCurrentFile' | 'fixInvalidDuration' | 'closeBatch' | 'concatBatch' | 'toggleKeyframeCutMode' | 'toggleCaptureFormat' | 'toggleStripAudio' | 'toggleStripThumbnail' | 'setStartTimeOffset' | 'toggleWaveformMode' | 'toggleShowThumbnails' | 'toggleShowKeyframes' | 'toggleSettings' | 'openSendReportDialog' | 'openFilesDialog' | 'exportYouTube' | 'closeCurrentFile' | 'quit'; +export type KeyboardAction = 'addSegment' | 'togglePlayResetSpeed' | 'togglePlayNoResetSpeed' | 'reducePlaybackRate' | 'reducePlaybackRateMore' | 'increasePlaybackRate' | 'increasePlaybackRateMore' | 'timelineToggleComfortZoom' | 'seekPreviousFrame' | 'seekNextFrame' | 'captureSnapshot' | 'setCutStart' | 'setCutEnd' | 'removeCurrentSegment' | 'cleanupFilesDialog' | 'splitCurrentSegment' | 'increaseRotation' | 'goToTimecode' | 'seekBackwards' | 'seekBackwards2' | 'seekBackwards3' | 'seekBackwardsPercent' | 'seekBackwardsPercent' | 'seekBackwardsKeyframe' | 'jumpCutStart' | 'seekForwards' | 'seekForwards2' | 'seekForwards3' | 'seekForwardsPercent' | 'seekForwardsPercent' | 'seekForwardsKeyframe' | 'jumpCutEnd' | 'jumpTimelineStart' | 'jumpTimelineEnd' | 'jumpFirstSegment' | 'jumpPrevSegment' | 'timelineZoomIn' | 'timelineZoomIn' | 'batchPreviousFile' | 'jumpLastSegment' | 'jumpNextSegment' | 'timelineZoomOut' | 'timelineZoomOut' | 'batchNextFile' | 'batchOpenSelectedFile' | 'batchOpenPreviousFile' | 'batchOpenNextFile' | 'undo' | 'undo' | 'redo' | 'redo' | 'copySegmentsToClipboard' | 'copySegmentsToClipboard' | 'toggleFullscreenVideo' | 'labelCurrentSegment' | 'export' | 'toggleKeyboardShortcuts' | 'closeActiveScreen' | 'increaseVolume' | 'decreaseVolume' | 'detectBlackScenes' | 'detectSilentScenes' | 'detectSceneChanges' | 'toggleLastCommands' | 'play' | 'pause' | 'reloadFile' | 'html5ify' | 'togglePlayOnlyCurrentSegment' | 'toggleLoopOnlyCurrentSegment' | 'toggleLoopStartEndOnlyCurrentSegment' | 'toggleLoopSelectedSegments' | 'editCurrentSegmentTags' | 'duplicateCurrentSegment' | 'reorderSegsByStartTime' | 'invertAllSegments' | 'fillSegmentsGaps' | 'shiftAllSegmentTimes' | 'alignSegmentTimesToKeyframes' | 'createSegmentsFromKeyframes' | 'createFixedDurationSegments' | 'createNumSegments' | 'createRandomSegments' | 'shuffleSegments' | 'combineOverlappingSegments' | 'combineSelectedSegments' | 'clearSegments' | 'toggleSegmentsList' | 'selectOnlyCurrentSegment' | 'deselectAllSegments' | 'selectAllSegments' | 'toggleCurrentSegmentSelected' | 'invertSelectedSegments' | 'removeSelectedSegments' | 'toggleStreamsSelector' | 'extractAllStreams' | 'showStreamsSelector' | 'showIncludeExternalStreamsDialog' | 'captureSnapshotAsCoverArt' | 'extractCurrentSegmentFramesAsImages' | 'extractSelectedSegmentsFramesAsImages' | 'convertFormatBatch' | 'convertFormatCurrentFile' | 'fixInvalidDuration' | 'closeBatch' | 'concatBatch' | 'toggleKeyframeCutMode' | 'toggleCaptureFormat' | 'toggleStripAudio' | 'toggleStripThumbnail' | 'setStartTimeOffset' | 'toggleWaveformMode' | 'toggleShowThumbnails' | 'toggleShowKeyframes' | 'toggleSettings' | 'openSendReportDialog' | 'openFilesDialog' | 'exportYouTube' | 'closeCurrentFile' | 'quit'; export interface KeyBinding { keys: string, @@ -72,6 +72,8 @@ export interface Config { outSegTemplate: string | undefined, keyboardSeekAccFactor: number, keyboardNormalSeekSpeed: number, + keyboardSeekSpeed2: number, + keyboardSeekSpeed3: number, treatInputFileModifiedTimeAsStart: boolean, treatOutputFileModifiedTimeAsStart: boolean | undefined | null, outFormatLocked: string | undefined,