shortcuts dev...
This commit is contained in:
@@ -9,7 +9,6 @@
|
|||||||
"@emotion/styled": "^11.10.8",
|
"@emotion/styled": "^11.10.8",
|
||||||
"@mui/icons-material": "^5.11.11",
|
"@mui/icons-material": "^5.11.11",
|
||||||
"@mui/material": "^5.11.12",
|
"@mui/material": "^5.11.12",
|
||||||
"@violentmonkey/shortcut": "^1.3.0",
|
|
||||||
"query-string": "^8.1.0",
|
"query-string": "^8.1.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
|||||||
@@ -489,4 +489,20 @@ export const I18N = {
|
|||||||
zh: `恢复默认`,
|
zh: `恢复默认`,
|
||||||
en: `Restore Default`,
|
en: `Restore Default`,
|
||||||
},
|
},
|
||||||
|
shortcuts_setting: {
|
||||||
|
zh: `快捷键设置`,
|
||||||
|
en: `Shortcuts Setting`,
|
||||||
|
},
|
||||||
|
toggle_translate_shortcut: {
|
||||||
|
zh: `开启翻译快捷键`,
|
||||||
|
en: `Toggle Translate Shortcut`,
|
||||||
|
},
|
||||||
|
toggle_style_shortcut: {
|
||||||
|
zh: `切换样式快捷键`,
|
||||||
|
en: `Toggle Style Shortcut`,
|
||||||
|
},
|
||||||
|
toggle_popup_shortcut: {
|
||||||
|
zh: `打开弹窗快捷键`,
|
||||||
|
en: `Open Popup Shortcut`,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -238,6 +238,16 @@ export const DEFAULT_TRANS_APIS = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 默认快捷键
|
||||||
|
export const OPT_SHORTCUT_TRANSLATE = "toggleTranslate";
|
||||||
|
export const OPT_SHORTCUT_STYLE = "toggleStyle";
|
||||||
|
export const OPT_SHORTCUT_POPUP = "togglePopup";
|
||||||
|
export const DEFAULT_SHORTCUTS = {
|
||||||
|
[OPT_SHORTCUT_TRANSLATE]: ["Alt", "q"],
|
||||||
|
[OPT_SHORTCUT_STYLE]: ["Alt", "c"],
|
||||||
|
[OPT_SHORTCUT_POPUP]: ["Alt", "k"],
|
||||||
|
};
|
||||||
|
|
||||||
export const TRANS_MIN_LENGTH = 5; // 最短翻译长度
|
export const TRANS_MIN_LENGTH = 5; // 最短翻译长度
|
||||||
export const TRANS_MAX_LENGTH = 5000; // 最长翻译长度
|
export const TRANS_MAX_LENGTH = 5000; // 最长翻译长度
|
||||||
export const TRANS_NEWLINE_LENGTH = 40; // 换行字符数
|
export const TRANS_NEWLINE_LENGTH = 40; // 换行字符数
|
||||||
@@ -256,6 +266,7 @@ export const DEFAULT_SETTING = {
|
|||||||
owSubrule: DEFAULT_OW_RULE, // 覆写订阅规则
|
owSubrule: DEFAULT_OW_RULE, // 覆写订阅规则
|
||||||
transApis: DEFAULT_TRANS_APIS, // 翻译接口
|
transApis: DEFAULT_TRANS_APIS, // 翻译接口
|
||||||
mouseKey: OPT_MOUSEKEY_DISABLE, // 鼠标悬停翻译
|
mouseKey: OPT_MOUSEKEY_DISABLE, // 鼠标悬停翻译
|
||||||
|
shortcuts: DEFAULT_SHORTCUTS, // 快捷键
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_RULES = [GLOBLA_RULE];
|
export const DEFAULT_RULES = [GLOBLA_RULE];
|
||||||
|
|||||||
22
src/hooks/Shortcut.js
Normal file
22
src/hooks/Shortcut.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { useCallback } from "react";
|
||||||
|
import { DEFAULT_SHORTCUTS } from "../config";
|
||||||
|
import { useSetting } from "./Setting";
|
||||||
|
|
||||||
|
export function useShortcut(action) {
|
||||||
|
const { setting, updateSetting } = useSetting();
|
||||||
|
const shortcuts = setting?.shortcuts || DEFAULT_SHORTCUTS;
|
||||||
|
|
||||||
|
const setShortcut = useCallback(
|
||||||
|
async (val) => {
|
||||||
|
await updateSetting({
|
||||||
|
shortcuts: {
|
||||||
|
...shortcuts,
|
||||||
|
[action]: val,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[action, shortcuts, updateSetting]
|
||||||
|
);
|
||||||
|
|
||||||
|
return { shortcut: shortcuts[action] || [], setShortcut };
|
||||||
|
}
|
||||||
@@ -139,3 +139,14 @@ export const sha256 = async (text, salt) => {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const genEventName = () => btoa(Math.random()).slice(3, 11);
|
export const genEventName = () => btoa(Math.random()).slice(3, 11);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断两个 Set 是否相同
|
||||||
|
* @param {*} a
|
||||||
|
* @param {*} b
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const isSameSet = (a, b) => {
|
||||||
|
const s = new Set([...a, ...b]);
|
||||||
|
return s.size === a.size && s.size === b.size;
|
||||||
|
};
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import Draggable from "./Draggable";
|
|||||||
import { useEffect, useState, useMemo, useCallback } from "react";
|
import { useEffect, useState, useMemo, useCallback } from "react";
|
||||||
import { SettingProvider } from "../../hooks/Setting";
|
import { SettingProvider } from "../../hooks/Setting";
|
||||||
import Popup from "../Popup";
|
import Popup from "../Popup";
|
||||||
import { debounce } from "../../libs/utils";
|
import { debounce, isSameSet } from "../../libs/utils";
|
||||||
import * as shortcut from "@violentmonkey/shortcut";
|
|
||||||
import { isGm } from "../../libs/client";
|
import { isGm } from "../../libs/client";
|
||||||
import Header from "../Popup/Header";
|
import Header from "../Popup/Header";
|
||||||
|
import { DEFAULT_SHORTCUTS, OPT_SHORTCUT_TRANSLATE } from "../../config";
|
||||||
|
|
||||||
export default function Action({ translator, fab }) {
|
export default function Action({ translator, fab }) {
|
||||||
const fabWidth = 40;
|
const fabWidth = 40;
|
||||||
@@ -43,22 +43,55 @@ export default function Action({ translator, fab }) {
|
|||||||
setMoved(true);
|
setMoved(true);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// // 注册快捷键
|
||||||
|
// const handleKeydown = (e) => {
|
||||||
|
// if (!e.altKey) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if (e.code === "KeyQ") {
|
||||||
|
// translator.toggle();
|
||||||
|
// setShowPopup(false);
|
||||||
|
// } else if (e.code === "KeyC") {
|
||||||
|
// translator.toggleStyle();
|
||||||
|
// setShowPopup(false);
|
||||||
|
// } else if (e.code === "KeyK") {
|
||||||
|
// setShowPopup((pre) => !pre);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// window.addEventListener("keydown", handleKeydown);
|
||||||
|
// return () => {
|
||||||
|
// window.removeEventListener("keydown", handleKeydown);
|
||||||
|
// };
|
||||||
|
// }, [translator]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 注册快捷键
|
// 注册快捷键
|
||||||
shortcut.register("a-q", () => {
|
const shortcuts = translator.setting.shortcuts || DEFAULT_SHORTCUTS;
|
||||||
translator.toggle();
|
const keys = new Set();
|
||||||
setShowPopup(false);
|
|
||||||
});
|
|
||||||
shortcut.register("a-c", () => {
|
|
||||||
translator.toggleStyle();
|
|
||||||
setShowPopup(false);
|
|
||||||
});
|
|
||||||
shortcut.register("a-k", () => {
|
|
||||||
setShowPopup((pre) => !pre);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const handleKeydown = (e) => {
|
||||||
|
console.log("keydown", e);
|
||||||
|
e.code && keys.add(e.key);
|
||||||
|
|
||||||
|
console.log("keys", keys);
|
||||||
|
const isSame = isSameSet(
|
||||||
|
keys,
|
||||||
|
new Set(shortcuts[OPT_SHORTCUT_TRANSLATE])
|
||||||
|
);
|
||||||
|
console.log("isSame", keys, isSame);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyup = (e) => {
|
||||||
|
console.log("keyup", e);
|
||||||
|
keys.delete(e.key);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("keydown", handleKeydown);
|
||||||
|
window.addEventListener("keyup", handleKeyup);
|
||||||
return () => {
|
return () => {
|
||||||
shortcut.disable();
|
window.removeEventListener("keydown", handleKeydown);
|
||||||
|
window.removeEventListener("keyup", handleKeyup);
|
||||||
};
|
};
|
||||||
}, [translator]);
|
}, [translator]);
|
||||||
|
|
||||||
|
|||||||
@@ -12,13 +12,89 @@ import { limitNumber } from "../../libs/utils";
|
|||||||
import { useI18n } from "../../hooks/I18n";
|
import { useI18n } from "../../hooks/I18n";
|
||||||
import { useAlert } from "../../hooks/Alert";
|
import { useAlert } from "../../hooks/Alert";
|
||||||
import { isExt } from "../../libs/client";
|
import { isExt } from "../../libs/client";
|
||||||
|
import IconButton from "@mui/material/IconButton";
|
||||||
|
import EditIcon from "@mui/icons-material/Edit";
|
||||||
|
import Grid from "@mui/material/Grid";
|
||||||
import {
|
import {
|
||||||
UI_LANGS,
|
UI_LANGS,
|
||||||
TRANS_NEWLINE_LENGTH,
|
TRANS_NEWLINE_LENGTH,
|
||||||
CACHE_NAME,
|
CACHE_NAME,
|
||||||
OPT_MOUSEKEY_ALL,
|
OPT_MOUSEKEY_ALL,
|
||||||
OPT_MOUSEKEY_DISABLE,
|
OPT_MOUSEKEY_DISABLE,
|
||||||
|
OPT_SHORTCUT_TRANSLATE,
|
||||||
|
OPT_SHORTCUT_STYLE,
|
||||||
|
OPT_SHORTCUT_POPUP,
|
||||||
} from "../../config";
|
} from "../../config";
|
||||||
|
import { useEffect, useState, useRef } from "react";
|
||||||
|
import { useShortcut } from "../../hooks/Shortcut";
|
||||||
|
|
||||||
|
function ShortcutItem({ action, label }) {
|
||||||
|
const { shortcut, setShortcut } = useShortcut(action);
|
||||||
|
const [disabled, setDisabled] = useState(true);
|
||||||
|
const [focused, setFocus] = useState(false);
|
||||||
|
const [formval, setFormval] = useState(shortcut);
|
||||||
|
const inputRef = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!disabled) {
|
||||||
|
inputRef.current.focus();
|
||||||
|
setFormval([]);
|
||||||
|
}
|
||||||
|
}, [disabled]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!focused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const keys = new Set();
|
||||||
|
const handleKeydown = (e) => {
|
||||||
|
// console.log("keydown", e);
|
||||||
|
e.code && keys.add(e.key);
|
||||||
|
setFormval([...keys]);
|
||||||
|
};
|
||||||
|
const handleKeyup = (e) => {
|
||||||
|
// console.log("keyup", e);
|
||||||
|
keys.delete(e.key);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("keydown", handleKeydown);
|
||||||
|
window.addEventListener("keyup", handleKeyup);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("keydown", handleKeydown);
|
||||||
|
window.removeEventListener("keyup", handleKeyup);
|
||||||
|
};
|
||||||
|
}, [focused]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack direction="row">
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={label}
|
||||||
|
name={label}
|
||||||
|
value={formval.join(" + ")}
|
||||||
|
fullWidth
|
||||||
|
inputRef={inputRef}
|
||||||
|
disabled={disabled}
|
||||||
|
onFocus={(e) => {
|
||||||
|
setFocus(true);
|
||||||
|
}}
|
||||||
|
onBlur={(e) => {
|
||||||
|
setFocus(false);
|
||||||
|
setDisabled(true);
|
||||||
|
setShortcut(formval);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
onClick={() => {
|
||||||
|
setDisabled(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{<EditIcon />}
|
||||||
|
</IconButton>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function Settings() {
|
export default function Settings() {
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
@@ -151,7 +227,7 @@ export default function Settings() {
|
|||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
{isExt && (
|
{isExt ? (
|
||||||
<FormControl size="small">
|
<FormControl size="small">
|
||||||
<InputLabel>{i18n("if_clear_cache")}</InputLabel>
|
<InputLabel>{i18n("if_clear_cache")}</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
@@ -169,6 +245,27 @@ export default function Settings() {
|
|||||||
</Link>
|
</Link>
|
||||||
</FormHelperText>
|
</FormHelperText>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
) : (
|
||||||
|
<Grid container rowSpacing={2} columns={12}>
|
||||||
|
<Grid item xs={12} sm={12} md={4} lg={4}>
|
||||||
|
<ShortcutItem
|
||||||
|
action={OPT_SHORTCUT_TRANSLATE}
|
||||||
|
label={i18n("toggle_translate_shortcut")}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={12} md={4} lg={4}>
|
||||||
|
<ShortcutItem
|
||||||
|
action={OPT_SHORTCUT_STYLE}
|
||||||
|
label={i18n("toggle_style_shortcut")}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={12} md={4} lg={4}>
|
||||||
|
<ShortcutItem
|
||||||
|
action={OPT_SHORTCUT_POPUP}
|
||||||
|
label={i18n("toggle_popup_shortcut")}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
Reference in New Issue
Block a user