mirror of
https://github.com/mifi/lossless-cut.git
synced 2024-11-22 02:12:30 +01:00
add keyboard actions
- Open previous file `batchOpenPreviousFile` - Open next `filebatchOpenNextFile` closes #1926
This commit is contained in:
parent
55a915b2f7
commit
ef59dbda84
@ -51,12 +51,14 @@ const defaultKeyBindings = [
|
||||
{ keys: 'ctrl+up', action: 'timelineZoomIn' },
|
||||
{ keys: 'command+up', action: 'timelineZoomIn' },
|
||||
{ keys: 'shift+up', action: 'batchPreviousFile' },
|
||||
{ keys: 'ctrl+shift+up', action: 'batchOpenPreviousFile' },
|
||||
|
||||
{ keys: 'pagedown', action: 'jumpLastSegment' },
|
||||
{ keys: 'down', action: 'jumpNextSegment' },
|
||||
{ keys: 'ctrl+down', action: 'timelineZoomOut' },
|
||||
{ keys: 'command+down', action: 'timelineZoomOut' },
|
||||
{ keys: 'shift+down', action: 'batchNextFile' },
|
||||
{ keys: 'ctrl+shift+down', action: 'batchOpenNextFile' },
|
||||
|
||||
{ keys: 'shift+enter', action: 'batchOpenSelectedFile' },
|
||||
|
||||
|
29
src/App.tsx
29
src/App.tsx
@ -1653,19 +1653,24 @@ function App() {
|
||||
}
|
||||
}, [userOpenSingleFile, setWorking, filePath]);
|
||||
|
||||
const batchFileJump = useCallback((direction) => {
|
||||
const batchFileJump = useCallback((direction: number, alsoOpen: boolean) => {
|
||||
if (batchFiles.length === 0) return;
|
||||
|
||||
let newSelectedBatchFiles: string[];
|
||||
if (selectedBatchFiles.length === 0) {
|
||||
setSelectedBatchFiles([batchFiles[0]!.path]);
|
||||
return;
|
||||
}
|
||||
newSelectedBatchFiles = [batchFiles[0]!.path];
|
||||
} else {
|
||||
const selectedFilePath = selectedBatchFiles[direction > 0 ? selectedBatchFiles.length - 1 : 0];
|
||||
const pathIndex = batchFiles.findIndex(({ path }) => path === selectedFilePath);
|
||||
if (pathIndex === -1) return;
|
||||
const nextFile = batchFiles[pathIndex + direction];
|
||||
if (!nextFile) return;
|
||||
setSelectedBatchFiles([nextFile.path]);
|
||||
}, [batchFiles, selectedBatchFiles]);
|
||||
newSelectedBatchFiles = [nextFile.path];
|
||||
}
|
||||
|
||||
setSelectedBatchFiles(newSelectedBatchFiles);
|
||||
if (alsoOpen) batchOpenSingleFile(newSelectedBatchFiles[0]);
|
||||
}, [batchFiles, batchOpenSingleFile, selectedBatchFiles]);
|
||||
|
||||
const batchOpenSelectedFile = useCallback(() => {
|
||||
if (selectedBatchFiles.length === 0) return;
|
||||
@ -2032,7 +2037,7 @@ function App() {
|
||||
|
||||
type MainKeyboardAction = Exclude<KeyboardAction, 'closeActiveScreen' | 'toggleKeyboardShortcuts'>;
|
||||
|
||||
const mainActions = useMemo<Record<MainKeyboardAction, ((a: { keyup?: boolean | undefined }) => boolean) | ((a: { keyup?: boolean | undefined }) => void)>>(() => {
|
||||
const mainActions = useMemo(() => {
|
||||
async function exportYouTube() {
|
||||
if (!checkFileOpened()) return;
|
||||
|
||||
@ -2043,7 +2048,7 @@ function App() {
|
||||
seekAccelerationRef.current = 1;
|
||||
}
|
||||
|
||||
return {
|
||||
const ret: Record<MainKeyboardAction, ((a: { keyup?: boolean | undefined }) => 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
|
||||
togglePlayNoResetSpeed: () => togglePlay(),
|
||||
@ -2099,8 +2104,10 @@ function App() {
|
||||
jumpTimelineEnd,
|
||||
timelineZoomIn: () => { zoomRel(1); return false; },
|
||||
timelineZoomOut: () => { zoomRel(-1); return false; },
|
||||
batchPreviousFile: () => batchFileJump(-1),
|
||||
batchNextFile: () => batchFileJump(1),
|
||||
batchPreviousFile: () => batchFileJump(-1, false),
|
||||
batchNextFile: () => batchFileJump(1, false),
|
||||
batchOpenPreviousFile: () => batchFileJump(-1, true),
|
||||
batchOpenNextFile: () => batchFileJump(1, true),
|
||||
batchOpenSelectedFile,
|
||||
closeBatch,
|
||||
removeCurrentSegment: () => removeCutSegment(currentSegIndexSafe),
|
||||
@ -2172,6 +2179,8 @@ function App() {
|
||||
showIncludeExternalStreamsDialog,
|
||||
toggleFullscreenVideo,
|
||||
};
|
||||
|
||||
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]);
|
||||
|
||||
const getKeyboardAction = useCallback((action: MainKeyboardAction) => mainActions[action], [mainActions]);
|
||||
|
@ -126,7 +126,7 @@ const KeyboardShortcuts = memo(({
|
||||
|
||||
const { mouseWheelZoomModifierKey } = useUserSettings();
|
||||
|
||||
const { actionsMap, extraLinesPerCategory } = useMemo<{ actionsMap: ActionsMap, extraLinesPerCategory: Record<Category, ReactNode> }>(() => {
|
||||
const { actionsMap, extraLinesPerCategory } = useMemo(() => {
|
||||
const playbackCategory = t('Playback');
|
||||
const selectivePlaybackCategory = t('Playback/preview segments only');
|
||||
const seekingCategory = t('Seeking');
|
||||
@ -137,26 +137,8 @@ const KeyboardShortcuts = memo(({
|
||||
const otherCategory = t('Other operations');
|
||||
const streamsCategory = t('Tracks');
|
||||
|
||||
return {
|
||||
extraLinesPerCategory: {
|
||||
[zoomOperationsCategory]: [
|
||||
<div key="1" style={{ ...rowStyle, alignItems: 'center' }}>
|
||||
<Text>{t('Zoom in/out timeline')}</Text>
|
||||
<div style={{ flexGrow: 1 }} />
|
||||
<FaMouse style={{ marginRight: 3 }} />
|
||||
<Text>{t('Mouse scroll/wheel up/down')}</Text>
|
||||
</div>,
|
||||
|
||||
<div key="2" style={{ ...rowStyle, alignItems: 'center' }}>
|
||||
<Text>{t('Pan timeline')}</Text>
|
||||
<div style={{ flexGrow: 1 }} />
|
||||
{getModifier(mouseWheelZoomModifierKey).map((v) => <kbd key={v} style={{ marginRight: '.7em' }}>{v}</kbd>)}
|
||||
<FaMouse style={{ marginRight: 3 }} />
|
||||
<Text>{t('Mouse scroll/wheel up/down')}</Text>
|
||||
</div>,
|
||||
],
|
||||
},
|
||||
actionsMap: {
|
||||
// eslint-disable-next-line no-shadow
|
||||
const actionsMap: ActionsMap = {
|
||||
toggleLastCommands: {
|
||||
name: t('Last ffmpeg commands'),
|
||||
},
|
||||
@ -506,10 +488,18 @@ const KeyboardShortcuts = memo(({
|
||||
name: t('Previous file'),
|
||||
category: batchFilesCategory,
|
||||
},
|
||||
batchOpenPreviousFile: {
|
||||
name: t('Open previous file'),
|
||||
category: batchFilesCategory,
|
||||
},
|
||||
batchNextFile: {
|
||||
name: t('Next file'),
|
||||
category: batchFilesCategory,
|
||||
},
|
||||
batchOpenNextFile: {
|
||||
name: t('Open next file'),
|
||||
category: batchFilesCategory,
|
||||
},
|
||||
batchOpenSelectedFile: {
|
||||
name: t('Open selected file'),
|
||||
category: batchFilesCategory,
|
||||
@ -604,7 +594,31 @@ const KeyboardShortcuts = memo(({
|
||||
name: t('Quit LosslessCut'),
|
||||
category: otherCategory,
|
||||
},
|
||||
} satisfies ActionsMap,
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
const extraLinesPerCategory: Record<Category, ReactNode> = {
|
||||
[zoomOperationsCategory]: [
|
||||
<div key="1" style={{ ...rowStyle, alignItems: 'center' }}>
|
||||
<Text>{t('Zoom in/out timeline')}</Text>
|
||||
<div style={{ flexGrow: 1 }} />
|
||||
<FaMouse style={{ marginRight: 3 }} />
|
||||
<Text>{t('Mouse scroll/wheel up/down')}</Text>
|
||||
</div>,
|
||||
|
||||
<div key="2" style={{ ...rowStyle, alignItems: 'center' }}>
|
||||
<Text>{t('Pan timeline')}</Text>
|
||||
<div style={{ flexGrow: 1 }} />
|
||||
{getModifier(mouseWheelZoomModifierKey).map((v) => <kbd key={v} style={{ marginRight: '.7em' }}>{v}</kbd>)}
|
||||
<FaMouse style={{ marginRight: 3 }} />
|
||||
<Text>{t('Mouse scroll/wheel up/down')}</Text>
|
||||
</div>,
|
||||
],
|
||||
};
|
||||
|
||||
return {
|
||||
extraLinesPerCategory,
|
||||
actionsMap,
|
||||
};
|
||||
}, [currentCutSeg, mouseWheelZoomModifierKey, t]);
|
||||
|
||||
|
2
types.ts
2
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' | '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' | '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 interface KeyBinding {
|
||||
keys: string,
|
||||
|
Loading…
Reference in New Issue
Block a user