@@ -2,6 +2,7 @@ import React, { useEffect, useRef, useState } from "react";
22import { css } from "@emotion/react" ;
33import { SegmentsList as CuttingSegmentsList , Waveforms } from "./Timeline" ;
44import {
5+ addCueAtIndex ,
56 selectCurrentlyAt ,
67 selectSelectedSubtitleById ,
78 selectSelectedSubtitleId ,
@@ -25,6 +26,7 @@ import { ThemedTooltip } from "./Tooltip";
2526import { useTranslation } from "react-i18next" ;
2627import { useHotkeys } from "react-hotkeys-hook" ;
2728import { KEYMAP } from "../globalKeys" ;
29+ import { shallowEqual } from "react-redux" ;
2830
2931/**
3032 * Copy-paste of the timeline in Video.tsx, so that we can make some small adjustments,
@@ -39,6 +41,7 @@ const SubtitleTimeline: React.FC = () => {
3941 const dispatch = useAppDispatch ( ) ;
4042 const duration = useAppSelector ( selectDuration ) ;
4143 const currentlyAt = useAppSelector ( selectCurrentlyAt ) ;
44+ const subtitleId = useAppSelector ( selectSelectedSubtitleId , shallowEqual ) ;
4245
4346 const { ref, width = 1 } = useResizeObserver < HTMLDivElement > ( ) ;
4447 const refTop = useRef < HTMLElement > ( null ) ;
@@ -71,6 +74,17 @@ const SubtitleTimeline: React.FC = () => {
7174
7275 const [ keyboardJumpDelta , setKeyboardJumpDelta ] = useState ( 1000 ) ; // In milliseconds. For keyboard navigation
7376
77+ // Callback for adding subtitle segment by hotkey
78+ const addCue = ( time : number ) => {
79+ dispatch ( addCueAtIndex ( {
80+ identifier : subtitleId ,
81+ cueIndex : - 1 ,
82+ text : "" ,
83+ startTime : time ,
84+ endTime : time + 5000 ,
85+ } ) ) ;
86+ } ;
87+
7488 // Callbacks for keyboard controls
7589 // TODO: Better increases and decreases than ten intervals
7690 // TODO: Additional helpful controls (e.g. jump to start/end of segment/next segment)
@@ -94,6 +108,11 @@ const SubtitleTimeline: React.FC = () => {
94108 ( ) => setKeyboardJumpDelta ( keyboardJumpDelta => Math . max ( keyboardJumpDelta / 10 , 1 ) ) ,
95109 { } , [ keyboardJumpDelta ] ,
96110 ) ;
111+ useHotkeys (
112+ KEYMAP . subtitleList . addCue . key ,
113+ ( ) => addCue ( currentlyAt ) ,
114+ { } , [ currentlyAt ] ,
115+ ) ;
97116
98117 // Callback for the scroll container
99118 const onEndScroll = ( e : ScrollEvent ) => {
@@ -102,6 +121,14 @@ const SubtitleTimeline: React.FC = () => {
102121 const offsetX = refTop . current . scrollLeft ;
103122 const scrollLeftMax = ( refTop . current . scrollWidth - refTop . current . clientWidth ) ;
104123 dispatch ( setCurrentlyAt ( ( offsetX / scrollLeftMax ) * ( duration ) ) ) ;
124+
125+ // Blur active element after scrolling, to ensure hotkeys are working
126+ // This is a little hack to work around focus getting stuck in textarea elements from the subtitle list
127+ try {
128+ ( document . activeElement as HTMLElement ) . blur ( ) ;
129+ } catch ( _e ) {
130+ console . error ( "Tried to blur active element, but active element cannot be blurred." ) ;
131+ }
105132 }
106133 } ;
107134
0 commit comments