add shortcut shift+j for toggling keyboard shortcut dialog #654

also allow resetting key config #726
pull/982/head
Mikael Finstad 2022-02-20 20:12:58 +08:00
rodzic 1a59be3e75
commit c2cb1f5501
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 25AB36E3E81CBC26
4 zmienionych plików z 41 dodań i 7 usunięć

Wyświetl plik

@ -62,6 +62,7 @@ const defaultKeyBindings = [
{ keys: 'e', action: 'export' }, { keys: 'e', action: 'export' },
{ keys: 'h', action: 'toggleHelp' }, { keys: 'h', action: 'toggleHelp' },
{ keys: 'shift+/', action: 'toggleKeyboardShortcuts' },
{ keys: 'escape', action: 'closeActiveScreen' }, { keys: 'escape', action: 'closeActiveScreen' },
]; ];

Wyświetl plik

@ -197,7 +197,7 @@ const App = memo(() => {
const isCustomFormatSelected = fileFormat !== detectedFileFormat; const isCustomFormatSelected = fileFormat !== detectedFileFormat;
const { const {
captureFormat, setCaptureFormat, customOutDir, setCustomOutDir, keyframeCut, setKeyframeCut, preserveMovData, setPreserveMovData, movFastStart, setMovFastStart, avoidNegativeTs, setAvoidNegativeTs, autoMerge, setAutoMerge, timecodeFormat, setTimecodeFormat, invertCutSegments, setInvertCutSegments, autoExportExtraStreams, setAutoExportExtraStreams, askBeforeClose, setAskBeforeClose, enableAskForImportChapters, setEnableAskForImportChapters, enableAskForFileOpenAction, setEnableAskForFileOpenAction, playbackVolume, setPlaybackVolume, autoSaveProjectFile, setAutoSaveProjectFile, wheelSensitivity, setWheelSensitivity, invertTimelineScroll, setInvertTimelineScroll, language, setLanguage, ffmpegExperimental, setFfmpegExperimental, hideNotifications, setHideNotifications, autoLoadTimecode, setAutoLoadTimecode, autoDeleteMergedSegments, setAutoDeleteMergedSegments, exportConfirmEnabled, setExportConfirmEnabled, segmentsToChapters, setSegmentsToChapters, preserveMetadataOnMerge, setPreserveMetadataOnMerge, simpleMode, setSimpleMode, outSegTemplate, setOutSegTemplate, keyboardSeekAccFactor, setKeyboardSeekAccFactor, keyboardNormalSeekSpeed, setKeyboardNormalSeekSpeed, enableTransferTimestamps, setEnableTransferTimestamps, outFormatLocked, setOutFormatLocked, safeOutputFileName, setSafeOutputFileName, enableAutoHtml5ify, setEnableAutoHtml5ify, segmentsToChaptersOnly, setSegmentsToChaptersOnly, keyBindings, setKeyBindings, captureFormat, setCaptureFormat, customOutDir, setCustomOutDir, keyframeCut, setKeyframeCut, preserveMovData, setPreserveMovData, movFastStart, setMovFastStart, avoidNegativeTs, setAvoidNegativeTs, autoMerge, setAutoMerge, timecodeFormat, setTimecodeFormat, invertCutSegments, setInvertCutSegments, autoExportExtraStreams, setAutoExportExtraStreams, askBeforeClose, setAskBeforeClose, enableAskForImportChapters, setEnableAskForImportChapters, enableAskForFileOpenAction, setEnableAskForFileOpenAction, playbackVolume, setPlaybackVolume, autoSaveProjectFile, setAutoSaveProjectFile, wheelSensitivity, setWheelSensitivity, invertTimelineScroll, setInvertTimelineScroll, language, setLanguage, ffmpegExperimental, setFfmpegExperimental, hideNotifications, setHideNotifications, autoLoadTimecode, setAutoLoadTimecode, autoDeleteMergedSegments, setAutoDeleteMergedSegments, exportConfirmEnabled, setExportConfirmEnabled, segmentsToChapters, setSegmentsToChapters, preserveMetadataOnMerge, setPreserveMetadataOnMerge, simpleMode, setSimpleMode, outSegTemplate, setOutSegTemplate, keyboardSeekAccFactor, setKeyboardSeekAccFactor, keyboardNormalSeekSpeed, setKeyboardNormalSeekSpeed, enableTransferTimestamps, setEnableTransferTimestamps, outFormatLocked, setOutFormatLocked, safeOutputFileName, setSafeOutputFileName, enableAutoHtml5ify, setEnableAutoHtml5ify, segmentsToChaptersOnly, setSegmentsToChaptersOnly, keyBindings, setKeyBindings, resetKeyBindings,
} = useUserPreferences(); } = useUserPreferences();
const { const {
@ -1626,6 +1626,8 @@ const App = memo(() => {
setStartTimeOffset(newStartTimeOffset); setStartTimeOffset(newStartTimeOffset);
}, [startTimeOffset]); }, [startTimeOffset]);
const toggleKeyboardShortcuts = useCallback(() => setKeyboardShortcutsVisible((v) => !v), []);
const onKeyPress = useCallback(({ action, keyup }) => { const onKeyPress = useCallback(({ action, keyup }) => {
function seekReset() { function seekReset() {
seekAccelerationRef.current = 1; seekAccelerationRef.current = 1;
@ -1723,6 +1725,11 @@ const App = memo(() => {
return false; return false;
} }
if (action === 'toggleKeyboardShortcuts') {
toggleKeyboardShortcuts();
return false;
}
if (concatDialogVisible || keyboardShortcutsVisible) { if (concatDialogVisible || keyboardShortcutsVisible) {
return true; // don't allow any further hotkeys return true; // don't allow any further hotkeys
} }
@ -1740,7 +1747,7 @@ const App = memo(() => {
if (match) return bubble; if (match) return bubble;
return true; // bubble the event return true; // bubble the event
}, [addCutSegment, askSetStartTimeOffset, batchFileJump, captureSnapshot, changePlaybackRate, cleanupFilesDialog, clearSegments, closeBatch, closeExportConfirm, concatCurrentBatch, concatDialogVisible, convertFormatBatch, createFixedDurationSegments, createNumSegments, currentSegIndexSafe, cutSegmentsHistory, exportConfirmVisible, extractAllStreams, goToTimecode, increaseRotation, invertAllCutSegments, jumpCutEnd, jumpCutStart, jumpSeg, jumpTimelineEnd, jumpTimelineStart, keyboardNormalSeekSpeed, keyboardSeekAccFactor, keyboardShortcutsVisible, onExportConfirm, onExportPress, onLabelSegmentPress, removeCutSegment, reorderSegsByStartTime, seekClosestKeyframe, seekRel, seekRelPercent, setCutEnd, setCutStart, shortStep, shuffleSegments, splitCurrentSegment, timelineToggleComfortZoom, toggleCaptureFormat, toggleHelp, toggleKeyframeCut, togglePlay, toggleSegmentsList, toggleStreamsSelector, toggleStripAudio, userHtml5ifyCurrentFile, zoomRel]); }, [addCutSegment, askSetStartTimeOffset, batchFileJump, captureSnapshot, changePlaybackRate, cleanupFilesDialog, clearSegments, closeBatch, closeExportConfirm, concatCurrentBatch, concatDialogVisible, convertFormatBatch, createFixedDurationSegments, createNumSegments, currentSegIndexSafe, cutSegmentsHistory, exportConfirmVisible, extractAllStreams, goToTimecode, increaseRotation, invertAllCutSegments, jumpCutEnd, jumpCutStart, jumpSeg, jumpTimelineEnd, jumpTimelineStart, keyboardNormalSeekSpeed, keyboardSeekAccFactor, keyboardShortcutsVisible, onExportConfirm, onExportPress, onLabelSegmentPress, removeCutSegment, reorderSegsByStartTime, seekClosestKeyframe, seekRel, seekRelPercent, setCutEnd, setCutStart, shortStep, shuffleSegments, splitCurrentSegment, timelineToggleComfortZoom, toggleCaptureFormat, toggleHelp, toggleKeyboardShortcuts, toggleKeyframeCut, togglePlay, toggleSegmentsList, toggleStreamsSelector, toggleStripAudio, userHtml5ifyCurrentFile, zoomRel]);
useKeyboard({ keyBindings, onKeyPress }); useKeyboard({ keyBindings, onKeyPress });
@ -2481,7 +2488,7 @@ const App = memo(() => {
<ConcatDialog isShown={batchFiles.length > 0 && concatDialogVisible} onHide={() => setConcatDialogVisible(false)} initialPaths={batchFilePaths} onConcat={mergeFiles} segmentsToChapters={segmentsToChapters} setSegmentsToChapters={setSegmentsToChapters} setAlwaysConcatMultipleFiles={setAlwaysConcatMultipleFiles} alwaysConcatMultipleFiles={alwaysConcatMultipleFiles} preserveMetadataOnMerge={preserveMetadataOnMerge} setPreserveMetadataOnMerge={setPreserveMetadataOnMerge} preserveMovData={preserveMovData} setPreserveMovData={setPreserveMovData} /> <ConcatDialog isShown={batchFiles.length > 0 && concatDialogVisible} onHide={() => setConcatDialogVisible(false)} initialPaths={batchFilePaths} onConcat={mergeFiles} segmentsToChapters={segmentsToChapters} setSegmentsToChapters={setSegmentsToChapters} setAlwaysConcatMultipleFiles={setAlwaysConcatMultipleFiles} alwaysConcatMultipleFiles={alwaysConcatMultipleFiles} preserveMetadataOnMerge={preserveMetadataOnMerge} setPreserveMetadataOnMerge={setPreserveMetadataOnMerge} preserveMovData={preserveMovData} setPreserveMovData={setPreserveMovData} />
<KeyboardShortcuts isShown={keyboardShortcutsVisible} onHide={() => setKeyboardShortcutsVisible(false)} keyBindings={keyBindings} setKeyBindings={setKeyBindings} currentCutSeg={currentCutSeg} /> <KeyboardShortcuts isShown={keyboardShortcutsVisible} onHide={() => setKeyboardShortcutsVisible(false)} keyBindings={keyBindings} setKeyBindings={setKeyBindings} currentCutSeg={currentCutSeg} resetKeyBindings={resetKeyBindings} />
</div> </div>
</ThemeProvider> </ThemeProvider>
); );

Wyświetl plik

@ -100,7 +100,7 @@ const CreateBinding = memo(({
const rowStyle = { display: 'flex', alignItems: 'center', margin: '6px 0' }; const rowStyle = { display: 'flex', alignItems: 'center', margin: '6px 0' };
const KeyboardShortcuts = memo(({ const KeyboardShortcuts = memo(({
keyBindings, setKeyBindings, currentCutSeg, keyBindings, setKeyBindings, resetKeyBindings, currentCutSeg,
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -136,7 +136,11 @@ const KeyboardShortcuts = memo(({
toggleHelp: { toggleHelp: {
name: t('Show/hide help screen'), name: t('Show/hide help screen'),
}, },
toggleKeyboardShortcuts: {
name: t('Keyboard & mouse shortcuts'),
},
// playbackCategory
togglePlayResetSpeed: { togglePlayResetSpeed: {
name: t('Play/pause'), name: t('Play/pause'),
category: playbackCategory, category: playbackCategory,
@ -162,6 +166,7 @@ const KeyboardShortcuts = memo(({
category: playbackCategory, category: playbackCategory,
}, },
// seekingCategory
seekPreviousFrame: { seekPreviousFrame: {
name: t('Step backward 1 frame'), name: t('Step backward 1 frame'),
category: seekingCategory, category: seekingCategory,
@ -209,6 +214,7 @@ const KeyboardShortcuts = memo(({
category: seekingCategory, category: seekingCategory,
}, },
// segmentsAndCutpointsCategory
addSegment: { addSegment: {
name: t('Add cut segment'), name: t('Add cut segment'),
category: segmentsAndCutpointsCategory, category: segmentsAndCutpointsCategory,
@ -272,6 +278,7 @@ const KeyboardShortcuts = memo(({
category: segmentsAndCutpointsCategory, category: segmentsAndCutpointsCategory,
}, },
// streamsCategory
toggleStreamsSelector: { toggleStreamsSelector: {
name: t('Edit tracks / metadata tags'), name: t('Edit tracks / metadata tags'),
category: streamsCategory, category: streamsCategory,
@ -281,6 +288,7 @@ const KeyboardShortcuts = memo(({
category: streamsCategory, category: streamsCategory,
}, },
// zoomOperationsCategory
timelineZoomIn: { timelineZoomIn: {
name: t('Zoom in timeline'), name: t('Zoom in timeline'),
category: zoomOperationsCategory, category: zoomOperationsCategory,
@ -294,6 +302,7 @@ const KeyboardShortcuts = memo(({
category: zoomOperationsCategory, category: zoomOperationsCategory,
}, },
// outputCategory
export: { export: {
name: t('Export segment(s)'), name: t('Export segment(s)'),
category: outputCategory, category: outputCategory,
@ -315,6 +324,7 @@ const KeyboardShortcuts = memo(({
category: outputCategory, category: outputCategory,
}, },
// batchFilesCategory
batchPreviousFile: { batchPreviousFile: {
name: t('Previous file'), name: t('Previous file'),
category: batchFilesCategory, category: batchFilesCategory,
@ -332,6 +342,7 @@ const KeyboardShortcuts = memo(({
category: batchFilesCategory, category: batchFilesCategory,
}, },
// otherCategory
toggleKeyframeCutMode: { toggleKeyframeCutMode: {
name: t('Cut mode'), name: t('Cut mode'),
category: otherCategory, category: otherCategory,
@ -380,6 +391,14 @@ const KeyboardShortcuts = memo(({
setKeyBindings((existingBindings) => existingBindings.filter((existingBinding) => !(existingBinding.keys === keys && existingBinding.action === action))); setKeyBindings((existingBindings) => existingBindings.filter((existingBinding) => !(existingBinding.keys === keys && existingBinding.action === action)));
}, [setKeyBindings, t]); }, [setKeyBindings, t]);
const onResetClick = useCallback(() => {
// eslint-disable-next-line no-alert
if (!window.confirm(t('Are you sure?'))) return;
resetKeyBindings();
}, [resetKeyBindings, t]);
const onAddBindingClick = useCallback((action) => { const onAddBindingClick = useCallback((action) => {
setCreatingBinding(action); setCreatingBinding(action);
}, []); }, []);
@ -448,13 +467,15 @@ const KeyboardShortcuts = memo(({
))} ))}
</div> </div>
<Button intent="danger" onClick={onResetClick}>{t('Reset')}</Button>
<CreateBinding actionsMap={actionsMap} action={creatingBinding} setCreatingBinding={setCreatingBinding} onNewKeyBindingConfirmed={onNewKeyBindingConfirmed} /> <CreateBinding actionsMap={actionsMap} action={creatingBinding} setCreatingBinding={setCreatingBinding} onNewKeyBindingConfirmed={onNewKeyBindingConfirmed} />
</> </>
); );
}); });
const KeyboardShortcutsDialog = memo(({ const KeyboardShortcutsDialog = memo(({
isShown, onHide, keyBindings, setKeyBindings, currentCutSeg, isShown, onHide, keyBindings, setKeyBindings, resetKeyBindings, currentCutSeg,
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -468,7 +489,7 @@ const KeyboardShortcutsDialog = memo(({
onConfirm={onHide} onConfirm={onHide}
topOffset="3vh" topOffset="3vh"
> >
{isShown ? <KeyboardShortcuts keyBindings={keyBindings} setKeyBindings={setKeyBindings} currentCutSeg={currentCutSeg} /> : <div />} {isShown ? <KeyboardShortcuts keyBindings={keyBindings} setKeyBindings={setKeyBindings} currentCutSeg={currentCutSeg} resetKeyBindings={resetKeyBindings} /> : <div />}
</Dialog> </Dialog>
); );
}); });

Wyświetl plik

@ -1,4 +1,4 @@
import { useEffect, useState, useRef } from 'react'; import { useEffect, useState, useRef, useCallback } from 'react';
import i18n from 'i18next'; import i18n from 'i18next';
import { errorToast } from '../util'; import { errorToast } from '../util';
@ -102,6 +102,10 @@ export default () => {
useEffect(() => safeSetConfig('segmentsToChaptersOnly', segmentsToChaptersOnly), [segmentsToChaptersOnly]); useEffect(() => safeSetConfig('segmentsToChaptersOnly', segmentsToChaptersOnly), [segmentsToChaptersOnly]);
const [keyBindings, setKeyBindings] = useState(safeGetConfig('keyBindings')); const [keyBindings, setKeyBindings] = useState(safeGetConfig('keyBindings'));
useEffect(() => safeSetConfig('keyBindings', keyBindings), [keyBindings]); useEffect(() => safeSetConfig('keyBindings', keyBindings), [keyBindings]);
const resetKeyBindings = useCallback(() => {
configStore.reset('keyBindings');
setKeyBindings(safeGetConfig('keyBindings'));
}, []);
// NOTE! This useEffect must be placed after all usages of firstUpdateRef.current (safeSetConfig) // NOTE! This useEffect must be placed after all usages of firstUpdateRef.current (safeSetConfig)
useEffect(() => { useEffect(() => {
@ -182,5 +186,6 @@ export default () => {
setSegmentsToChaptersOnly, setSegmentsToChaptersOnly,
keyBindings, keyBindings,
setKeyBindings, setKeyBindings,
resetKeyBindings,
}; };
}; };