diff --git a/src/biz/Body.tsx b/src/biz/Body.tsx index 6743ed8..d68470d 100644 --- a/src/biz/Body.tsx +++ b/src/biz/Body.tsx @@ -43,6 +43,7 @@ import {getSummarize} from '../util/biz_util' import {openUrl} from '@kky002/kky-util' import Markdown from '../components/Markdown' import {random} from 'lodash-es' +import useKeyService from '../hooks/useKeyService' const Body = () => { const dispatch = useAppDispatch() @@ -207,6 +208,9 @@ const Body = () => { dispatch(setAskFold(!askFold)) }, [askFold, dispatch]) + // service + useKeyService() + // 自动滚动 useEffect(() => { if (checkAutoScroll && curOffsetTop && autoScroll && !needScroll) { @@ -304,6 +308,13 @@ const Body = () => { segmentIdx={segmentIdx} bodyRef={bodyRef}/>)} {/* tip */} +
快捷键提示
+ + {/*
*/} {/*
💡提示💡
*/} {/*
可以尝试将概览生成的内容粘贴到 { {/* } */} {/*
*/}
-
+
BibiGPT logoBibiGPT diff --git a/src/biz/CompactSegmentItem.tsx b/src/biz/CompactSegmentItem.tsx index e091e3e..6457e49 100644 --- a/src/biz/CompactSegmentItem.tsx +++ b/src/biz/CompactSegmentItem.tsx @@ -9,8 +9,9 @@ const CompactSegmentItem = (props: { isIn: boolean last: boolean moveCallback: (event: any) => void + move2Callback: (event: any) => void }) => { - const {item, idx, last, isIn, moveCallback} = props + const {item, idx, last, isIn, moveCallback, move2Callback} = props const transResult = useAppSelector(state => state.env.transResults[idx]) const envData = useAppSelector(state => state.env.envData) const fontSize = useAppSelector(state => state.env.envData.fontSize) @@ -19,7 +20,7 @@ const CompactSegmentItem = (props: { const display = useMemo(() => getDisplay(envData.transDisplay, item.content, transText), [envData.transDisplay, item.content, transText]) return
- + {display.main} {display.sub && ({display.sub})} {!last && ','} diff --git a/src/biz/NormalSegmentItem.tsx b/src/biz/NormalSegmentItem.tsx index d984154..4f3b72d 100644 --- a/src/biz/NormalSegmentItem.tsx +++ b/src/biz/NormalSegmentItem.tsx @@ -9,8 +9,9 @@ const NormalSegmentItem = (props: { idx: number isIn: boolean moveCallback: (event: any) => void + move2Callback: (event: any) => void }) => { - const {item, idx, isIn, moveCallback} = props + const {item, idx, isIn, moveCallback, move2Callback} = props const transResult = useAppSelector(state => state.env.transResults[idx]) const envData = useAppSelector(state => state.env.envData) const fontSize = useAppSelector(state => state.env.envData.fontSize) @@ -19,7 +20,7 @@ const NormalSegmentItem = (props: { const display = useMemo(() => getDisplay(envData.transDisplay, item.content, transText), [envData.transDisplay, item.content, transText]) return
+ onClick={moveCallback} onDoubleClick={move2Callback}>
{formatTime(item.from)}
{display.main}
diff --git a/src/biz/SegmentCard.tsx b/src/biz/SegmentCard.tsx index 66fa963..289627c 100644 --- a/src/biz/SegmentCard.tsx +++ b/src/biz/SegmentCard.tsx @@ -46,7 +46,7 @@ const SummarizeItemOverview = (props: { if (event.altKey) { // 复制 navigator.clipboard.writeText(overviewItem.key).catch(console.error) } else { - move(time) + move(time, false) } }, [overviewItem.key, move, time]) diff --git a/src/biz/SegmentItem.tsx b/src/biz/SegmentItem.tsx index 80e2956..0e42e43 100644 --- a/src/biz/SegmentItem.tsx +++ b/src/biz/SegmentItem.tsx @@ -33,7 +33,15 @@ const SegmentItem = (props: { if (event.altKey) { // 复制 navigator.clipboard.writeText(item.content).catch(console.error) } else { - move(item.from) + move(item.from, false) + } + }, [item.content, item.from, move]) + + const move2Callback = useCallback((event: any) => { + if (event.altKey) { // 复制 + navigator.clipboard.writeText(item.content).catch(console.error) + } else { + move(item.from, true) } }, [item.content, item.from, move]) @@ -63,6 +71,7 @@ const SegmentItem = (props: { isIn={isIn} last={last} moveCallback={moveCallback} + move2Callback={move2Callback} /> : } diff --git a/src/chrome/content-script.cjs b/src/chrome/content-script.cjs index 9b876f4..5882c19 100644 --- a/src/chrome/content-script.cjs +++ b/src/chrome/content-script.cjs @@ -158,6 +158,9 @@ window.addEventListener("message", (event) => { const video = getVideoElement() if (video) { video.currentTime = data.time + if (data.togglePause) { + video.paused ? video.play() : video.pause() + } } } diff --git a/src/hooks/useKeyService.ts b/src/hooks/useKeyService.ts new file mode 100644 index 0000000..d346304 --- /dev/null +++ b/src/hooks/useKeyService.ts @@ -0,0 +1,59 @@ +import {useEffect} from 'react' +import {useMemoizedFn} from 'ahooks/es' +import {useAppSelector} from './redux' +import useSubtitle from './useSubtitle' + +const useKeyService = () => { + const curIdx = useAppSelector(state => state.env.curIdx) + const data = useAppSelector(state => state.env.data) + const {move} = useSubtitle() + + const onKeyDown = useMemoizedFn((e: KeyboardEvent) => { + // 有按其他控制键时,不触发 + if (e.ctrlKey || e.metaKey || e.shiftKey) { + return + } + + let cursorInInput = false + if (document.activeElement != null) { + const tagName = document.activeElement.tagName + if (tagName === 'INPUT' || tagName === 'TEXTAREA') { + cursorInInput = true + } + } + let prevent = false + + // up arrow + if (e.key === 'ArrowUp') { + if (curIdx && (data != null) && !cursorInInput) { + prevent = true + const newCurIdx = Math.max(curIdx - 1, 0) + move(data.body[newCurIdx].from, false) + } + } + // down arrow + if (e.key === 'ArrowDown') { + if (curIdx !== undefined && (data != null) && !cursorInInput) { + prevent = true + const newCurIdx = Math.min(curIdx + 1, data.body.length - 1) + move(data.body[newCurIdx].from, false) + } + } + + // 阻止默认事件 + if (prevent) { + e.preventDefault() + e.stopPropagation() + } + }) + + // 检测快捷键 + useEffect(() => { + document.addEventListener('keydown', onKeyDown) + return () => { + document.removeEventListener('keydown', onKeyDown) + } + }, [onKeyDown]) +} + +export default useKeyService diff --git a/src/hooks/useSubtitle.ts b/src/hooks/useSubtitle.ts index a63eedf..26987b3 100644 --- a/src/hooks/useSubtitle.ts +++ b/src/hooks/useSubtitle.ts @@ -5,8 +5,8 @@ import {setNeedScroll} from '../redux/envReducer' const useSubtitle = () => { const dispatch = useAppDispatch() - const move = useCallback((time: number) => { - window.parent.postMessage({type: 'move', time}, '*') + const move = useCallback((time: number, togglePause: boolean) => { + window.parent.postMessage({type: 'move', time, togglePause}, '*') }, []) const scrollIntoView = useCallback((ref: React.RefObject) => {