siyuan/app/src/boot/globalEvent/keydown.ts

1811 lines
74 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
copyPlainText,
isMac,
isNotCtrl,
isOnlyMeta,
updateHotkeyTip,
writeText
} from "../../protyle/util/compatibility";
import {matchAuxiliaryHotKey, matchHotKey} from "../../protyle/util/hotKey";
import {openSearch} from "../../search/spread";
import {
hasClosestBlock,
hasClosestByAttribute,
hasClosestByClassName,
hasTopClosestByTag,
} from "../../protyle/util/hasClosest";
import {newFile} from "../../util/newFile";
import {Constants} from "../../constants";
import {openSetting} from "../../config";
import {getInstanceById} from "../../layout/util";
import {closeTabByType, copyTab, getActiveTab, getDockByType, resizeTabs, switchTabByIndex} from "../../layout/tabUtil";
import {Tab} from "../../layout/Tab";
import {Editor} from "../../editor";
import {setEditMode} from "../../protyle/util/setEditMode";
import {rename} from "../../editor/rename";
import {Files} from "../../layout/dock/Files";
import {newDailyNote} from "../../util/mount";
import {hideElements} from "../../protyle/ui/hideElements";
import {fetchPost} from "../../util/fetch";
import {goBack, goForward} from "../../util/backForward";
import {onGet} from "../../protyle/util/onGet";
import {getDisplayName, getNotebookName, getTopPaths, movePathTo, moveToPath} from "../../util/pathName";
import {openFileById} from "../../editor/util";
import {getAllDocks, getAllModels, getAllTabs} from "../../layout/getAll";
import {openGlobalSearch} from "../../search/util";
import {focusBlock, focusByOffset, focusByRange, getSelectionOffset} from "../../protyle/util/selection";
import {initFileMenu, initNavigationMenu} from "../../menus/navigation";
import {bindMenuKeydown} from "../../menus/Menu";
import {Dialog} from "../../dialog";
import {unicode2Emoji} from "../../emoji";
import {deleteFiles} from "../../editor/deleteFile";
import {escapeHtml} from "../../util/escape";
import {syncGuide} from "../../sync/syncGuide";
import {showPopover} from "../../block/popover";
import {getStartEndElement, goEnd, goHome} from "../../protyle/wysiwyg/commonHotkey";
import {getNextFileLi, getPreviousFileLi} from "../../protyle/wysiwyg/getBlock";
import {editor} from "../../config/editor";
import {hintMoveBlock} from "../../protyle/hint/extend";
import {Backlink} from "../../layout/dock/Backlink";
/// #if !BROWSER
import {setZoom} from "../../layout/topBar";
import {ipcRenderer} from "electron";
/// #endif
import {openHistory} from "../../history/history";
import {openCard, openCardByData} from "../../card/openCard";
import {lockScreen} from "../../dialog/processSystem";
import {isWindow} from "../../util/functions";
import {reloadProtyle} from "../../protyle/util/reload";
import {fullscreen, updateReadonly} from "../../protyle/breadcrumb/action";
import {openRecentDocs} from "../../business/openRecentDocs";
import {App} from "../../index";
import {commandPanel} from "../../plugin/commandPanel";
import {openBacklink, openGraph, openOutline, toggleDockBar} from "../../layout/dock/util";
import {workspaceMenu} from "../../menus/workspace";
import {resize} from "../../protyle/util/resize";
import {Search} from "../../search";
import {Custom} from "../../layout/dock/Custom";
import {Protyle} from "../../protyle";
import {transaction} from "../../protyle/wysiwyg/transaction";
import {quickMakeCard} from "../../card/makeCard";
import {copyPNG} from "../../menus/util";
import {getContentByInlineHTML} from "../../protyle/wysiwyg/keydown";
import {searchKeydown} from "./searchKeydown";
import {openNewWindow} from "../../window/openNewWindow";
import {historyKeydown} from "../../history/keydown";
import {zoomOut} from "../../menus/protyle";
import {openSearchAV} from "../../protyle/render/av/relation";
import * as dayjs from "dayjs";
import {getPlainText} from "../../protyle/util/paste";
const switchDialogEvent = (app: App, event: MouseEvent) => {
event.preventDefault();
let target = event.target as HTMLElement;
while (!target.isSameNode(switchDialog.element)) {
if (target.classList.contains("b3-list-item")) {
const currentType = target.getAttribute("data-type");
if (currentType) {
if (currentType === "riffCard") {
openCard(app);
} else {
getDockByType(currentType).toggleModel(currentType, true);
}
} else {
const currentId = target.getAttribute("data-id");
getAllTabs().find(item => {
if (item.id === currentId) {
item.parent.switchTab(item.headElement);
item.parent.showHeading();
return true;
}
});
}
switchDialog.destroy();
switchDialog = undefined;
break;
}
target = target.parentElement;
}
};
const dialogArrow = (app: App, element: HTMLElement, event: KeyboardEvent) => {
let currentLiElement = element.querySelector(".b3-list-item--focus");
if (currentLiElement) {
currentLiElement.classList.remove("b3-list-item--focus");
if (event.key === "ArrowUp") {
if (currentLiElement.previousElementSibling) {
currentLiElement.previousElementSibling.classList.add("b3-list-item--focus");
} else {
currentLiElement.parentElement.lastElementChild.classList.add("b3-list-item--focus");
}
} else if (event.key === "ArrowDown") {
if (currentLiElement.nextElementSibling) {
currentLiElement.nextElementSibling.classList.add("b3-list-item--focus");
} else {
currentLiElement.parentElement.firstElementChild.classList.add("b3-list-item--focus");
}
} else if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
const sideElement = currentLiElement.parentElement.previousElementSibling || currentLiElement.parentElement.nextElementSibling;
if (sideElement) {
const tempLiElement = sideElement.querySelector(`[data-index="${currentLiElement.getAttribute("data-index")}"]`) || sideElement.lastElementChild;
if (tempLiElement) {
tempLiElement.classList.add("b3-list-item--focus");
} else {
currentLiElement.classList.add("b3-list-item--focus");
}
} else {
currentLiElement.classList.add("b3-list-item--focus");
}
} else if (event.key === "Enter") {
const currentType = currentLiElement.getAttribute("data-type");
if (currentType) {
if (currentType === "riffCard") {
openCard(app);
} else {
getDockByType(currentType).toggleModel(currentType, true);
}
} else {
openFileById({
app,
id: currentLiElement.getAttribute("data-node-id"),
action: [Constants.CB_GET_FOCUS, Constants.CB_GET_SCROLL]
});
}
hideElements(["dialog"]);
return;
}
currentLiElement = element.querySelector(".b3-list-item--focus");
const rootId = currentLiElement.getAttribute("data-node-id");
const pathElement = element.querySelector(".switch-doc__path");
if (rootId) {
fetchPost("/api/filetree/getFullHPathByID", {
id: rootId
}, (response) => {
pathElement.innerHTML = escapeHtml(response.data);
});
} else {
pathElement.innerHTML = currentLiElement.querySelector(".b3-list-item__text").innerHTML;
}
const currentRect = currentLiElement.getBoundingClientRect();
const currentParentRect = currentLiElement.parentElement.getBoundingClientRect();
if (currentRect.top < currentParentRect.top) {
currentLiElement.scrollIntoView(true);
} else if (currentRect.bottom > currentParentRect.bottom) {
currentLiElement.scrollIntoView(false);
}
}
};
const editKeydown = (app: App, event: KeyboardEvent) => {
let protyle: IProtyle;
let range: Range;
if (getSelection().rangeCount > 0) {
range = getSelection().getRangeAt(0);
}
const activePanelElement = document.querySelector(".layout__tab--active");
let isFileFocus = false;
if (activePanelElement && activePanelElement.classList.contains("sy__file")) {
isFileFocus = true;
}
if (range) {
window.siyuan.dialogs.find(item => {
if (item.editors) {
Object.keys(item.editors).find(key => {
if (item.editors[key].protyle.element.contains(range.startContainer)) {
protyle = item.editors[key].protyle;
// https://github.com/siyuan-note/siyuan/issues/9384
isFileFocus = false;
return true;
}
});
if (protyle) {
return true;
}
}
});
}
const activeTab = getActiveTab();
if (!protyle && activeTab) {
if (activeTab.model instanceof Editor) {
protyle = activeTab.model.editor.protyle;
} else if (activeTab.model instanceof Search) {
if (activeTab.model.element.querySelector("#searchUnRefPanel").classList.contains("fn__none")) {
protyle = activeTab.model.editors.edit.protyle;
} else {
protyle = activeTab.model.editors.unRefEdit.protyle;
}
} else if (activeTab.model instanceof Custom && activeTab.model.data?.editor instanceof Protyle) {
protyle = activeTab.model.data.editor.protyle;
} else {
return false;
}
} else if (!protyle) {
if (!protyle && range) {
window.siyuan.blockPanels.find(item => {
item.editors.find(editorItem => {
if (editorItem.protyle.element.contains(range.startContainer)) {
protyle = editorItem.protyle;
return true;
}
});
if (protyle) {
return true;
}
});
}
const models = getAllModels();
if (!protyle) {
models.backlink.find(item => {
if (item.element.classList.contains("layout__tab--active")) {
if (range) {
item.editors.find(editor => {
if (editor.protyle.element.contains(range.startContainer)) {
protyle = editor.protyle;
return true;
}
});
}
if (!protyle && item.editors.length > 0) {
protyle = item.editors[0].protyle;
}
return true;
}
});
}
if (!protyle) {
models.editor.find(item => {
if (item.parent.headElement.classList.contains("item--focus")) {
protyle = item.editor.protyle;
return true;
}
});
}
if (!protyle) {
return false;
}
}
let searchKey = "";
if (matchHotKey(window.siyuan.config.keymap.general.replace.custom, event)) {
searchKey = Constants.DIALOG_REPLACE;
} else if (matchHotKey(window.siyuan.config.keymap.general.search.custom, event)) {
searchKey = Constants.DIALOG_SEARCH;
}
if (!isFileFocus && searchKey) {
if (range && protyle.element.contains(range.startContainer)) {
openSearch({
app,
hotkey: searchKey,
key: range.toString(),
notebookId: protyle.notebookId,
searchPath: protyle.path
});
} else {
openSearch({
app,
hotkey: searchKey,
});
}
event.preventDefault();
return true;
}
if (!isFileFocus && matchHotKey(window.siyuan.config.keymap.editor.general.quickMakeCard.custom, event)) {
if (protyle.title?.editElement.contains(range.startContainer)) {
quickMakeCard(protyle, [protyle.title.element]);
} else {
const selectElement: Element[] = [];
protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select").forEach(item => {
selectElement.push(item);
});
if (selectElement.length === 0) {
const nodeElement = hasClosestBlock(range.startContainer);
if (nodeElement) {
selectElement.push(nodeElement);
}
}
quickMakeCard(protyle, selectElement);
}
event.preventDefault();
return true;
}
if (!isFileFocus && matchHotKey(window.siyuan.config.keymap.general.addToDatabase.custom, event)) {
if (protyle.title?.editElement.contains(range.startContainer)) {
openSearchAV("", protyle.breadcrumb.element, (listItemElement) => {
const sourceIds: string[] = [protyle.block.rootID];
const avID = listItemElement.dataset.avId;
transaction(protyle, [{
action: "insertAttrViewBlock",
avID,
ignoreFillFilter: true,
srcIDs: sourceIds,
isDetached: false,
blockID: listItemElement.dataset.nodeId
}, {
action: "doUpdateUpdated",
id: listItemElement.dataset.nodeId,
data: dayjs().format("YYYYMMDDHHmmss"),
}], [{
action: "removeAttrViewBlock",
srcIDs: sourceIds,
avID,
}]);
focusByRange(range)
});
} else {
const selectElement: Element[] = [];
protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select").forEach(item => {
selectElement.push(item);
});
if (selectElement.length === 0) {
const nodeElement = hasClosestBlock(range.startContainer);
if (nodeElement) {
selectElement.push(nodeElement);
}
}
openSearchAV("", selectElement[0] as HTMLElement, (listItemElement) => {
const sourceIds: string[] = [];
selectElement.forEach(item => {
sourceIds.push(item.getAttribute("data-node-id"));
});
const avID = listItemElement.dataset.avId;
transaction(protyle, [{
action: "insertAttrViewBlock",
avID,
ignoreFillFilter: true,
srcIDs: sourceIds,
isDetached: false,
blockID: listItemElement.dataset.blockId
}, {
action: "doUpdateUpdated",
id: listItemElement.dataset.blockId,
data: dayjs().format("YYYYMMDDHHmmss"),
}], [{
action: "removeAttrViewBlock",
srcIDs: sourceIds,
avID,
}]);
focusByRange(range)
});
}
event.preventDefault();
return true;
}
if (!isFileFocus && matchHotKey(window.siyuan.config.keymap.editor.general.spaceRepetition.custom, event)) {
fetchPost("/api/riff/getTreeRiffDueCards", {rootID: protyle.block.rootID}, (response) => {
openCardByData(app, response.data, "doc", protyle.block.rootID, protyle.title?.editElement.textContent || window.siyuan.languages.untitled);
});
event.preventDefault();
return true;
}
if (!isFileFocus && matchHotKey(window.siyuan.config.keymap.general.move.custom, event)) {
let range: Range;
let nodeElement: false | HTMLElement;
if (getSelection().rangeCount > 0) {
range = getSelection().getRangeAt(0);
nodeElement = hasClosestBlock(range.startContainer);
}
if (protyle.title?.editElement.contains(range.startContainer)) {
movePathTo((toPath, toNotebook) => {
moveToPath([protyle.path], toNotebook[0], toPath[0]);
}, [protyle.path], range);
} else if (nodeElement && range && protyle.element.contains(range.startContainer)) {
let selectElements = Array.from(protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select"));
if (selectElements.length === 0) {
selectElements = [nodeElement];
}
movePathTo((toPath) => {
hintMoveBlock(toPath[0], selectElements, protyle);
});
}
event.preventDefault();
return true;
}
const target = event.target as HTMLElement;
if (target.tagName !== "TABLE" && ["INPUT", "TEXTAREA"].includes(target.tagName)) {
return false;
}
// ctrl+home 光标移动到顶
if (!event.altKey && !event.shiftKey && isOnlyMeta(event) && event.key === "Home") {
goHome(protyle);
hideElements(["select"], protyle);
event.stopPropagation();
event.preventDefault();
return;
}
// ctrl+end 光标移动到尾
if (!event.altKey && !event.shiftKey && isOnlyMeta(event) && event.key === "End") {
goEnd(protyle);
hideElements(["select"], protyle);
event.stopPropagation();
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.editor.general.exitFocus.custom, event)) {
event.preventDefault();
zoomOut({protyle, id: protyle.block.rootID, focusId: protyle.block.id});
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.general.switchReadonly.custom, event)) {
event.preventDefault();
updateReadonly(protyle.breadcrumb.element.parentElement.querySelector('.block__icon[data-type="readonly"]'), protyle);
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.general.backlinks.custom, event)) {
event.preventDefault();
if (range) {
const refElement = hasClosestByAttribute(range.startContainer, "data-type", "block-ref");
if (refElement) {
openBacklink({
app: protyle.app,
blockId: refElement.dataset.id,
});
return true;
}
}
openBacklink({
app: protyle.app,
blockId: protyle.block.id,
rootId: protyle.block.rootID,
useBlockId: protyle.block.showAll,
title: protyle.title ? (protyle.title.editElement.textContent || window.siyuan.languages.untitled) : null,
});
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.general.graphView.custom, event)) {
event.preventDefault();
if (range) {
const refElement = hasClosestByAttribute(range.startContainer, "data-type", "block-ref");
if (refElement) {
openGraph({
app: protyle.app,
blockId: refElement.dataset.id,
});
return true;
}
}
openGraph({
app: protyle.app,
blockId: protyle.block.id,
rootId: protyle.block.rootID,
useBlockId: protyle.block.showAll,
title: protyle.title ? (protyle.title.editElement.textContent || window.siyuan.languages.untitled) : null,
});
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.general.outline.custom, event)) {
event.preventDefault();
const offset = getSelectionOffset(target);
openOutline(protyle);
// switchWnd 后range会被清空需要重新设置
focusByOffset(target, offset.start, offset.end);
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.general.copyPlainText.custom, event)) {
const nodeElement = hasClosestBlock(range.startContainer);
if (!nodeElement) {
return false;
}
if (range.toString() === "") {
const selectsElement: HTMLElement[] = Array.from(protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select"));
let html = "";
if (selectsElement.length === 0) {
selectsElement.push(nodeElement);
}
selectsElement.forEach(item => {
html += getPlainText(item) + "\n";
});
copyPlainText(html.trimEnd());
} else {
copyPlainText(range.toString());
}
event.preventDefault();
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.general.refresh.custom, event)) {
reloadProtyle(protyle, true);
event.preventDefault();
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.general.fullscreen.custom, event)) {
fullscreen(protyle.element);
resize(protyle);
event.preventDefault();
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.general.preview.custom, event)) {
setEditMode(protyle, "preview");
event.preventDefault();
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.general.wysiwyg.custom, event) && !protyle.options.backlinkData) {
setEditMode(protyle, "wysiwyg");
protyle.scroll.lastScrollTop = 0;
fetchPost("/api/filetree/getDoc", {
id: protyle.block.parentID,
size: window.siyuan.config.editor.dynamicLoadBlocks,
}, getResponse => {
onGet({data: getResponse, protyle});
});
event.preventDefault();
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.general.copyBlockRef.custom, event)) {
event.preventDefault();
event.stopPropagation();
if (hasClosestByClassName(range.startContainer, "protyle-title")) {
fetchPost("/api/block/getRefText", {id: protyle.block.rootID}, (response) => {
writeText(`((${protyle.block.rootID} '${response.data}'))`);
});
} else {
const nodeElement = hasClosestBlock(range.startContainer);
if (!nodeElement) {
return false;
}
const selectElements = protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select");
let actionElement;
if (selectElements.length === 1) {
actionElement = selectElements[0];
} else {
const selectImgElement = nodeElement.querySelector(".img--select");
if (selectImgElement) {
copyPNG(selectImgElement.querySelector("img"));
return true;
}
actionElement = nodeElement;
}
const actionElementId = actionElement.getAttribute("data-node-id");
if (range.toString() !== "") {
getContentByInlineHTML(range, (content) => {
writeText(`((${actionElementId} "${content.trim()}"))`);
});
} else {
fetchPost("/api/block/getRefText", {id: actionElementId}, (response) => {
writeText(`((${actionElementId} '${response.data}'))`);
});
}
}
}
if (hasClosestByClassName(target, "protyle-title__input")) {
return false;
}
// 没有光标时,无法撤销 https://ld246.com/article/1624021111567
if (matchHotKey(window.siyuan.config.keymap.editor.general.undo.custom, event)) {
protyle.undo.undo(protyle);
event.preventDefault();
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.general.redo.custom, event)) {
protyle.undo.redo(protyle);
event.preventDefault();
return true;
}
return false;
};
const fileTreeKeydown = (app: App, event: KeyboardEvent) => {
const dockFile = getDockByType("file");
if (!dockFile) {
return false;
}
const files = dockFile.data.file as Files;
if (matchHotKey(window.siyuan.config.keymap.general.selectOpen1.custom, event)) {
event.preventDefault();
const element = document.querySelector(".layout__wnd--active > .fn__flex > .layout-tab-bar > .item--focus") ||
document.querySelector("ul.layout-tab-bar > .item--focus");
if (element) {
const tab = getInstanceById(element.getAttribute("data-id")) as Tab;
if (tab && tab.model instanceof Editor) {
tab.model.editor.protyle.wysiwyg.element.blur();
tab.model.editor.protyle.title.editElement.blur();
files.selectItem(tab.model.editor.protyle.notebookId, tab.model.editor.protyle.path);
}
}
dockFile.toggleModel("file", true);
return;
}
if (!files.element.parentElement.classList.contains("layout__tab--active")) {
return false;
}
let matchCommand = false;
app.plugins.find(item => {
item.commands.find(command => {
if (command.fileTreeCallback && matchHotKey(command.customHotkey, event)) {
matchCommand = true;
command.fileTreeCallback(files);
return true;
}
});
if (matchCommand) {
return true;
}
});
if (matchCommand) {
return true;
}
const liElements = Array.from(files.element.querySelectorAll(".b3-list-item--focus"));
if (liElements.length === 0) {
if (event.key.startsWith("Arrow") && isNotCtrl(event)) {
const liElement = files.element.querySelector(".b3-list-item");
if (liElement) {
liElement.classList.add("b3-list-item--focus");
}
event.preventDefault();
}
return false;
}
const topULElement = hasTopClosestByTag(liElements[0], "UL");
if (!topULElement) {
return false;
}
const notebookId = topULElement.getAttribute("data-url");
const pathString = liElements[0].getAttribute("data-path");
const isFile = liElements[0].getAttribute("data-type") === "navigation-file";
if (matchHotKey(window.siyuan.config.keymap.editor.general.spaceRepetition.custom, event)) {
if (isFile) {
const id = liElements[0].getAttribute("data-node-id");
fetchPost("/api/riff/getTreeRiffDueCards", {rootID: id}, (response) => {
openCardByData(app, response.data, "doc", id, getDisplayName(liElements[0].getAttribute("data-name"), false, true));
});
} else {
fetchPost("/api/riff/getNotebookRiffDueCards", {notebook: notebookId}, (response) => {
openCardByData(app, response.data, "notebook", notebookId, getNotebookName(notebookId));
});
}
}
if (matchHotKey(window.siyuan.config.keymap.editor.general.quickMakeCard.custom, event)) {
const blockIDs: string[] = [];
liElements.forEach(item => {
const id = item.getAttribute("data-node-id");
if (id) {
blockIDs.push(id);
}
});
if (blockIDs.length > 0) {
transaction(undefined, [{
action: "addFlashcards",
deckID: Constants.QUICK_DECK_ID,
blockIDs,
}], [{
action: "removeFlashcards",
deckID: Constants.QUICK_DECK_ID,
blockIDs,
}]);
}
event.preventDefault();
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.general.rename.custom, event)) {
window.siyuan.menus.menu.remove();
rename({
notebookId,
path: pathString,
name: isFile ? getDisplayName(liElements[0].getAttribute("data-name"), false, true) : getNotebookName(notebookId),
type: isFile ? "file" : "notebook",
});
event.preventDefault();
return true;
}
if (matchHotKey("⌘/", event)) {
const liRect = liElements[0].getBoundingClientRect();
if (isFile) {
initFileMenu(app, notebookId, pathString, liElements[0]).popup({
x: liRect.right - 15,
y: liRect.top + 15
});
} else {
initNavigationMenu(app, liElements[0] as HTMLElement).popup({x: liRect.right - 15, y: liRect.top + 15});
}
return true;
}
if (isFile && matchHotKey(window.siyuan.config.keymap.general.move.custom, event)) {
window.siyuan.menus.menu.remove();
const pathes = getTopPaths(liElements);
movePathTo((toPath, toNotebook) => {
moveToPath(pathes, toNotebook[0], toPath[0]);
}, pathes);
event.preventDefault();
return true;
}
if (isFile && matchHotKey(window.siyuan.config.keymap.editor.general.insertRight.custom, event)) {
window.siyuan.menus.menu.remove();
openFileById({
app,
id: liElements[0].getAttribute("data-node-id"),
action: [Constants.CB_GET_FOCUS],
position: "right",
});
event.preventDefault();
return true;
}
let searchKey = "";
if (matchHotKey(window.siyuan.config.keymap.general.replace.custom, event)) {
searchKey = Constants.DIALOG_REPLACE;
} else if (matchHotKey(window.siyuan.config.keymap.general.search.custom, event)) {
searchKey = Constants.DIALOG_SEARCH;
}
if (searchKey) {
window.siyuan.menus.menu.remove();
if (isFile) {
openSearch({
app,
hotkey: searchKey,
notebookId: notebookId,
searchPath: getDisplayName(pathString, false, true)
});
} else {
openSearch({
app,
hotkey: searchKey,
notebookId: notebookId,
});
}
event.preventDefault();
return true;
}
const target = event.target as HTMLElement;
if (["INPUT", "TEXTAREA"].includes(target.tagName) ||
hasClosestByAttribute(target, "contenteditable", null) ||
hasClosestByClassName(target, "protyle", true)) {
return false;
}
if (event.shiftKey) {
if (event.key === "ArrowUp") {
const startEndElement = getStartEndElement(liElements);
let previousElement: Element;
if (startEndElement.startElement.getBoundingClientRect().top >= startEndElement.endElement.getBoundingClientRect().top) {
previousElement = getPreviousFileLi(startEndElement.endElement) as Element;
if (previousElement) {
previousElement.classList.add("b3-list-item--focus");
previousElement.setAttribute("select-end", "true");
startEndElement.endElement.removeAttribute("select-end");
}
} else {
startEndElement.endElement.classList.remove("b3-list-item--focus");
startEndElement.endElement.removeAttribute("select-end");
previousElement = getPreviousFileLi(startEndElement.endElement) as Element;
if (previousElement) {
previousElement.setAttribute("select-end", "true");
}
}
if (previousElement) {
const previousRect = previousElement.getBoundingClientRect();
const fileRect = files.element.getBoundingClientRect();
if (previousRect.top < fileRect.top || previousRect.bottom > fileRect.bottom) {
previousElement.scrollIntoView(previousRect.top < fileRect.top);
}
}
} else if (event.key === "ArrowDown") {
const startEndElement = getStartEndElement(liElements);
let nextElement: Element;
if (startEndElement.startElement.getBoundingClientRect().top <= startEndElement.endElement.getBoundingClientRect().top) {
nextElement = getNextFileLi(startEndElement.endElement) as Element;
if (nextElement) {
nextElement.classList.add("b3-list-item--focus");
nextElement.setAttribute("select-end", "true");
startEndElement.endElement.removeAttribute("select-end");
}
} else {
startEndElement.endElement.classList.remove("b3-list-item--focus");
startEndElement.endElement.removeAttribute("select-end");
nextElement = getNextFileLi(startEndElement.endElement) as Element;
if (nextElement) {
nextElement.setAttribute("select-end", "true");
}
}
if (nextElement) {
const nextRect = nextElement.getBoundingClientRect();
const fileRect = files.element.getBoundingClientRect();
if (nextRect.top < fileRect.top || nextRect.bottom > fileRect.bottom) {
nextElement.scrollIntoView(nextRect.top < fileRect.top);
}
}
}
return;
} else if (isNotCtrl(event)) {
files.element.querySelector('[select-end="true"]')?.removeAttribute("select-end");
files.element.querySelector('[select-start="true"]')?.removeAttribute("select-start");
if ((event.key === "ArrowRight" && !liElements[0].querySelector(".b3-list-item__arrow--open") && !liElements[0].querySelector(".b3-list-item__toggle").classList.contains("fn__hidden")) ||
(event.key === "ArrowLeft" && liElements[0].querySelector(".b3-list-item__arrow--open"))) {
files.getLeaf(liElements[0], notebookId);
liElements.forEach((item, index) => {
if (index !== 0) {
item.classList.remove("b3-list-item--focus");
}
});
event.preventDefault();
return true;
}
if (event.key === "ArrowLeft") {
let parentElement = liElements[0].parentElement.previousElementSibling;
if (parentElement) {
if (parentElement.tagName !== "LI") {
parentElement = files.element.querySelector(".b3-list-item");
}
liElements.forEach((item) => {
item.classList.remove("b3-list-item--focus");
});
parentElement.classList.add("b3-list-item--focus");
const parentRect = parentElement.getBoundingClientRect();
const fileRect = files.element.getBoundingClientRect();
if (parentRect.top < fileRect.top || parentRect.bottom > fileRect.bottom) {
parentElement.scrollIntoView(parentRect.top < fileRect.top);
}
}
event.preventDefault();
return true;
}
if (event.key === "ArrowDown" || event.key === "ArrowRight") {
let nextElement = liElements[0];
while (nextElement) {
if (nextElement.nextElementSibling) {
if (nextElement.nextElementSibling.tagName === "UL") {
nextElement = nextElement.nextElementSibling.firstElementChild;
} else {
nextElement = nextElement.nextElementSibling;
}
break;
} else {
if (nextElement.parentElement.classList.contains("fn__flex-1")) {
break;
} else {
nextElement = nextElement.parentElement;
}
}
}
if (nextElement.classList.contains("b3-list-item")) {
liElements.forEach((item) => {
item.classList.remove("b3-list-item--focus");
});
nextElement.classList.add("b3-list-item--focus");
const nextRect = nextElement.getBoundingClientRect();
const fileRect = files.element.getBoundingClientRect();
if (nextRect.top < fileRect.top || nextRect.bottom > fileRect.bottom) {
nextElement.scrollIntoView(nextRect.top < fileRect.top);
}
}
event.preventDefault();
return true;
}
if (event.key === "ArrowUp") {
let previousElement = liElements[0];
while (previousElement) {
if (previousElement.previousElementSibling) {
if (previousElement.previousElementSibling.tagName === "LI") {
previousElement = previousElement.previousElementSibling;
} else {
const liElements = previousElement.previousElementSibling.querySelectorAll(".b3-list-item");
previousElement = liElements[liElements.length - 1];
}
break;
} else {
if (previousElement.parentElement.classList.contains("fn__flex-1")) {
break;
} else {
previousElement = previousElement.parentElement;
}
}
}
if (previousElement.classList.contains("b3-list-item")) {
liElements.forEach((item) => {
item.classList.remove("b3-list-item--focus");
});
previousElement.classList.add("b3-list-item--focus");
const previousRect = previousElement.getBoundingClientRect();
const fileRect = files.element.getBoundingClientRect();
if (previousRect.top < fileRect.top || previousRect.bottom > fileRect.bottom) {
previousElement.scrollIntoView(previousRect.top < fileRect.top);
}
}
event.preventDefault();
return true;
}
}
if (event.key === "Delete" || (event.key === "Backspace" && isMac())) {
window.siyuan.menus.menu.remove();
deleteFiles(liElements);
return true;
}
if (event.key === "Enter") {
window.siyuan.menus.menu.remove();
liElements.forEach(item => {
if (item.getAttribute("data-type") === "navigation-file") {
openFileById({app, id: item.getAttribute("data-node-id"), action: [Constants.CB_GET_FOCUS]});
} else {
const itemTopULElement = hasTopClosestByTag(item, "UL");
if (itemTopULElement) {
files.getLeaf(item, itemTopULElement.getAttribute("data-url"));
}
}
});
return true;
}
};
const panelTreeKeydown = (app: App, event: KeyboardEvent) => {
// 面板折叠展开操作
const target = event.target as HTMLElement;
if (["INPUT", "TEXTAREA"].includes(target.tagName) ||
hasClosestByAttribute(target, "contenteditable", null) ||
hasClosestByClassName(target, "protyle", true)) {
return false;
}
let activePanelElement = document.querySelector(".layout__tab--active");
if (!activePanelElement) {
Array.from(document.querySelectorAll(".layout__wnd--active .layout-tab-container > div")).find(item => {
if (!item.classList.contains("fn__none") && item.className.indexOf("sy__") > -1) {
activePanelElement = item;
return true;
}
});
}
if (!activePanelElement) {
return false;
}
if (activePanelElement.className.indexOf("sy__") === -1) {
return false;
}
let matchCommand = false;
app.plugins.find(item => {
item.commands.find(command => {
if (command.dockCallback && matchHotKey(command.customHotkey, event)) {
matchCommand = true;
command.dockCallback(activePanelElement as HTMLElement);
return true;
}
});
if (matchCommand) {
return true;
}
});
if (matchCommand) {
return true;
}
if (!matchHotKey(window.siyuan.config.keymap.editor.general.collapse.custom, event) &&
!matchHotKey(window.siyuan.config.keymap.editor.general.expand.custom, event) &&
!event.key.startsWith("Arrow") && event.key !== "Enter") {
return false;
}
if (!event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.collapse.custom, event)) {
const collapseElement = activePanelElement.querySelector('.block__icon[data-type="collapse"]');
if (collapseElement) {
collapseElement.dispatchEvent(new CustomEvent("click"));
event.preventDefault();
return true;
}
}
if (!event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.expand.custom, event)) {
const expandElement = activePanelElement.querySelector('.block__icon[data-type="expand"]');
if (expandElement) {
expandElement.dispatchEvent(new CustomEvent("click"));
event.preventDefault();
return true;
}
}
if (activePanelElement.classList.contains("sy__inbox") ||
activePanelElement.classList.contains("sy__globalGraph") ||
activePanelElement.classList.contains("sy__graph")) {
return false;
}
const model = (getInstanceById(activePanelElement.getAttribute("data-id"), window.siyuan.layout.layout) as Tab)?.model;
if (!model) {
return false;
}
let activeItemElement = activePanelElement.querySelector(".b3-list-item--focus");
if (!activeItemElement) {
activeItemElement = activePanelElement.querySelector(".b3-list .b3-list-item");
if (activeItemElement) {
activeItemElement.classList.add("b3-list-item--focus");
}
return false;
}
let tree = (model as Backlink).tree;
if (activeItemElement.parentElement.parentElement.classList.contains("backlinkMList")) {
tree = (model as Backlink).mTree;
}
if (!tree) {
return false;
}
if (event.key === "Enter") {
tree.click(activeItemElement);
event.preventDefault();
return true;
}
const arrowElement = activeItemElement.querySelector(".b3-list-item__arrow");
if ((event.key === "ArrowRight" && !arrowElement.classList.contains("b3-list-item__arrow--open") && !arrowElement.parentElement.classList.contains("fn__hidden")) ||
(event.key === "ArrowLeft" && arrowElement.classList.contains("b3-list-item__arrow--open") && !arrowElement.parentElement.classList.contains("fn__hidden"))) {
tree.toggleBlocks(activeItemElement);
event.preventDefault();
return true;
}
const ulElement = hasClosestByClassName(activeItemElement, "b3-list");
if (!ulElement) {
return false;
}
if (event.key === "ArrowLeft") {
let parentElement = activeItemElement.parentElement.previousElementSibling;
if (parentElement) {
if (parentElement.tagName !== "LI") {
parentElement = ulElement.querySelector(".b3-list-item");
}
activeItemElement.classList.remove("b3-list-item--focus");
parentElement.classList.add("b3-list-item--focus");
const parentRect = parentElement.getBoundingClientRect();
const scrollRect = ulElement.parentElement.getBoundingClientRect();
if (parentRect.top < scrollRect.top || parentRect.bottom > scrollRect.bottom) {
parentElement.scrollIntoView(parentRect.top < scrollRect.top);
}
}
event.preventDefault();
return true;
}
if (event.key === "ArrowDown" || event.key === "ArrowRight") {
let nextElement = activeItemElement;
while (nextElement) {
if (nextElement.nextElementSibling) {
if (nextElement.nextElementSibling.tagName === "UL") {
if (nextElement.nextElementSibling.classList.contains("fn__none")) { // 遇到折叠内容
if (nextElement.nextElementSibling.nextElementSibling) {
nextElement = nextElement.nextElementSibling.nextElementSibling;
}
} else {
nextElement = nextElement.nextElementSibling.firstElementChild;
}
} else if (nextElement.nextElementSibling.classList.contains("protyle")) { // backlink
if (nextElement.nextElementSibling.nextElementSibling) {
nextElement = nextElement.nextElementSibling.nextElementSibling;
}
} else {
nextElement = nextElement.nextElementSibling;
}
break;
} else {
if (nextElement.parentElement.classList.contains("fn__flex-1")) {
break;
} else {
nextElement = nextElement.parentElement;
}
}
}
if (nextElement.classList.contains("b3-list-item") && !nextElement.classList.contains("b3-list-item--focus")) {
activeItemElement.classList.remove("b3-list-item--focus");
nextElement.classList.add("b3-list-item--focus");
const nextRect = nextElement.getBoundingClientRect();
const scrollRect = ulElement.parentElement.getBoundingClientRect();
if (nextRect.top < scrollRect.top || nextRect.bottom > scrollRect.bottom) {
nextElement.scrollIntoView(nextRect.top < scrollRect.top);
}
}
event.preventDefault();
return true;
}
if (event.key === "ArrowUp") {
let previousElement = activeItemElement;
while (previousElement) {
if (previousElement.previousElementSibling) {
if (previousElement.previousElementSibling.tagName === "LI") {
previousElement = previousElement.previousElementSibling;
} else if (previousElement.previousElementSibling.classList.contains("protyle")) {
if (previousElement.previousElementSibling.previousElementSibling) {
previousElement = previousElement.previousElementSibling.previousElementSibling;
}
} else if (previousElement.previousElementSibling.tagName === "UL" && previousElement.previousElementSibling.classList.contains("fn__none")) { // 遇到折叠内容
if (previousElement.previousElementSibling.previousElementSibling) {
previousElement = previousElement.previousElementSibling.previousElementSibling;
}
} else {
const liElements = previousElement.previousElementSibling.querySelectorAll(".b3-list-item");
previousElement = liElements[liElements.length - 1];
}
break;
} else {
if (previousElement.parentElement.classList.contains("fn__flex-1")) {
break;
} else {
previousElement = previousElement.parentElement;
}
}
}
if (previousElement.classList.contains("b3-list-item") && !previousElement.classList.contains("b3-list-item--focus")) {
activeItemElement.classList.remove("b3-list-item--focus");
previousElement.classList.add("b3-list-item--focus");
const previousRect = previousElement.getBoundingClientRect();
const scrollRect = ulElement.parentElement.getBoundingClientRect();
if (previousRect.top < scrollRect.top || previousRect.bottom > scrollRect.bottom) {
previousElement.scrollIntoView(previousRect.top < scrollRect.top);
}
}
event.preventDefault();
return true;
}
return false;
};
let switchDialog: Dialog;
export const windowKeyDown = (app: App, event: KeyboardEvent) => {
// https://github.com/siyuan-note/siyuan/issues/9848 忘记为什么要阻止了 .av__mask 的情况,测了下没问题就先移除
if (document.getElementById("progress") || document.getElementById("errorLog") || event.isComposing) {
return;
}
const target = event.target as HTMLElement;
if (isNotCtrl(event) && !event.shiftKey && !event.altKey &&
!["INPUT", "TEXTAREA"].includes(target.tagName) &&
["0", "1", "2", "3", "4", "j", "k", "l", ";", "s", " ", "p", "enter", "a", "s", "d", "f", "q", "x"].includes(event.key.toLowerCase())) {
let cardElement: Element;
window.siyuan.dialogs.find(item => {
if (item.element.getAttribute("data-key") === Constants.DIALOG_OPENCARD) {
cardElement = item.element;
return true;
}
});
if (!cardElement) {
cardElement = document.querySelector(`.layout__wnd--active div[data-key="${Constants.DIALOG_OPENCARD}"]:not(.fn__none)`);
}
if (cardElement) {
event.preventDefault();
cardElement.dispatchEvent(new CustomEvent("click", {detail: event.key.toLowerCase()}));
return;
}
}
// 仅处理以下快捷键操作
if (isNotCtrl(event) && event.key !== "Escape" && !event.shiftKey && !event.altKey &&
Constants.KEYCODELIST[event.keyCode] !== "PageUp" &&
Constants.KEYCODELIST[event.keyCode] !== "PageDown" &&
event.key !== "Home" && event.key !== "End" &&
!/^F\d{1,2}$/.test(event.key) && event.key.indexOf("Arrow") === -1 && event.key !== "Enter" && event.key !== "Backspace" && event.key !== "Delete") {
return;
}
if (!event.altKey && !event.shiftKey && isOnlyMeta(event)) {
if ((isMac() ? event.key === "Meta" : event.key === "Control") || isOnlyMeta(event)) {
window.siyuan.ctrlIsPressed = true;
if ((event.key === "Meta" || event.key === "Control") &&
window.siyuan.config.editor.floatWindowMode === 1 && !event.repeat) {
showPopover(app);
}
} else {
window.siyuan.ctrlIsPressed = false;
}
}
if (!event.altKey && event.shiftKey && isNotCtrl(event)) {
if (event.key === "Shift") {
window.siyuan.shiftIsPressed = true;
if (!event.repeat) {
showPopover(app, true);
}
} else {
window.siyuan.shiftIsPressed = false;
}
}
if (event.altKey && !event.shiftKey && isNotCtrl(event)) {
if (event.key === "Alt") {
window.siyuan.altIsPressed = true;
} else {
window.siyuan.altIsPressed = false;
}
}
if (switchDialog &&
(matchAuxiliaryHotKey(window.siyuan.config.keymap.general.goToEditTabNext.custom, event) ||
matchAuxiliaryHotKey(window.siyuan.config.keymap.general.goToEditTabPrev.custom, event))
&& event.key.startsWith("Arrow")) {
dialogArrow(app, switchDialog.element, event);
return;
}
if (searchKeydown(app, event)) {
event.preventDefault();
event.stopPropagation();
return;
}
const isTabWindow = isWindow();
if (matchHotKey(window.siyuan.config.keymap.general.goToEditTabNext.custom, event) ||
matchHotKey(window.siyuan.config.keymap.general.goToEditTabPrev.custom, event)) {
if (switchDialog && switchDialog.element.parentElement) {
return;
}
let tabHtml = "";
let currentTabElement = document.querySelector(".layout__wnd--active ul.layout-tab-bar > .item--focus");
if (!currentTabElement) {
currentTabElement = document.querySelector("ul.layout-tab-bar > .item--focus");
}
if (currentTabElement) {
const currentId = currentTabElement.getAttribute("data-id");
getAllTabs().sort((itemA, itemB) => {
return itemA.headElement.getAttribute("data-activetime") > itemB.headElement.getAttribute("data-activetime") ? -1 : 1;
}).forEach((item, index) => {
let icon = `<svg class="b3-list-item__graphic"><use xlink:href="#${item.icon}"></use></svg>`;
let rootId = "";
const initData = item.headElement.getAttribute("data-initdata");
if (item.model instanceof Editor) {
rootId = ` data-node-id="${item.model.editor.protyle.block.rootID}"`;
icon = unicode2Emoji(item.docIcon || Constants.SIYUAN_IMAGE_FILE, "b3-list-item__graphic", true);
} else if (initData) {
const initDataObj = JSON.parse(initData);
if (initDataObj.instance === "Editor") {
rootId = ` data-node-id="${initDataObj.rootId}"`;
icon = unicode2Emoji(item.docIcon || Constants.SIYUAN_IMAGE_FILE, "b3-list-item__graphic", true);
}
}
tabHtml += `<li data-index="${index}" data-id="${item.id}"${rootId} class="b3-list-item${currentId === item.id ? " b3-list-item--focus" : ""}"${currentId === item.id ? ' data-original="true"' : ""}>${icon}<span class="b3-list-item__text">${escapeHtml(item.title)}</span></li>`;
});
}
let dockHtml = "";
if (!isTabWindow) {
dockHtml = `<ul class="b3-list b3-list--background" style="overflow: auto;width: 200px;">
<li data-type="riffCard" data-index="0" class="b3-list-item${!tabHtml ? " b3-list-item--focus" : ""}">
<svg class="b3-list-item__graphic"><use xlink:href="#iconRiffCard"></use></svg>
<span class="b3-list-item__text">${window.siyuan.languages.riffCard}</span>
<span class="b3-list-item__meta">${updateHotkeyTip(window.siyuan.config.keymap.general.riffCard.custom)}</span>
</li>`;
getAllDocks().forEach((item, index) => {
dockHtml += `<li data-type="${item.type}" data-index="${index + 1}" class="b3-list-item">
<svg class="b3-list-item__graphic"><use xlink:href="#${item.icon}"></use></svg>
<span class="b3-list-item__text">${item.title}</span>
<span class="b3-list-item__meta">${updateHotkeyTip(item.hotkey || "")}</span>
</li>`;
});
dockHtml = dockHtml + "</ul>";
}
hideElements(["dialog"]);
switchDialog = new Dialog({
positionId: Constants.DIALOG_SWITCHTAB,
title: window.siyuan.languages.switchTab,
content: `<div class="fn__flex-column switch-doc">
<input style="opacity: 0;height: 0.1px;box-sizing: border-box;margin: 0;padding: 0;border: 0;">
<div class="fn__flex" style="overflow:auto;">${dockHtml}
<ul${!isTabWindow ? "" : ' style="border-left:0"'} class="b3-list b3-list--background fn__flex-1">${tabHtml}</ul>
</div>
<div class="switch-doc__path"></div>
</div>`,
});
switchDialog.element.setAttribute("data-key", Constants.DIALOG_SWITCHTAB);
// 需移走光标,否则编辑器会继续监听并执行按键操作
switchDialog.element.querySelector("input").focus();
if (isMac()) {
switchDialog.element.addEventListener("contextmenu", (event) => {
switchDialogEvent(app, event);
});
}
switchDialog.element.addEventListener("click", (event) => {
switchDialogEvent(app, event);
});
return;
}
if (isNotCtrl(event) && !event.shiftKey && !event.altKey &&
(event.key.startsWith("Arrow") || event.key === "Enter")) {
const openRecentDocsDialog = window.siyuan.dialogs.find(item => {
if (item.element.getAttribute("data-key") === Constants.DIALOG_RECENTDOCS) {
return true;
}
});
if (openRecentDocsDialog) {
event.preventDefault();
dialogArrow(app, openRecentDocsDialog.element, event);
return;
}
}
if (matchHotKey(window.siyuan.config.keymap.general.recentDocs.custom, event)) {
openRecentDocs();
event.preventDefault();
return;
}
if (bindMenuKeydown(event)) {
event.preventDefault();
return;
}
if (["Home", "End", "ArrowUp", "ArrowDown"].includes(event.key)) {
let matchDialog: Dialog;
// 需找到最顶层的,因此不能用 find
window.siyuan.dialogs.forEach(item => {
if ([Constants.DIALOG_VIEWCARDS, Constants.DIALOG_HISTORYCOMPARE].includes(item.element.getAttribute("data-key"))) {
matchDialog = item;
}
});
if (matchDialog) {
if (matchDialog.element.getAttribute("data-key") === Constants.DIALOG_VIEWCARDS) {
matchDialog.element.dispatchEvent(new CustomEvent("click", {detail: event.key.toLowerCase()}));
} else if (matchDialog.element.getAttribute("data-key") === Constants.DIALOG_HISTORYCOMPARE) {
historyKeydown(event, matchDialog);
}
event.preventDefault();
return;
}
}
/// #if !BROWSER
if (matchHotKey("⌘=", event) && !hasClosestByClassName(target, "pdf__outer")) {
setZoom("zoomIn");
event.preventDefault();
return;
}
if (matchHotKey("⌘0", event)) {
setZoom("restore");
event.preventDefault();
return;
}
if (matchHotKey("⌘-", event) && !hasClosestByClassName(target, "pdf__outer")) {
setZoom("zoomOut");
event.preventDefault();
return;
}
/// #endif
if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.syncNow.custom, event)) {
event.preventDefault();
syncGuide(app);
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.commandPanel.custom, event)) {
event.preventDefault();
commandPanel(app);
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.editReadonly.custom, event)) {
event.preventDefault();
editor.setReadonly(!window.siyuan.config.editor.readOnly);
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.lockScreen.custom, event)) {
lockScreen(app);
event.preventDefault();
return;
}
if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.dataHistory.custom, event)) {
if (!window.siyuan.config.readonly) {
openHistory(app);
}
event.preventDefault();
return;
}
if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.toggleDock.custom, event)) {
toggleDockBar(document.querySelector("#barDock use"));
event.preventDefault();
return;
}
if (!isTabWindow && !window.siyuan.config.readonly && matchHotKey(window.siyuan.config.keymap.general.config.custom, event)) {
openSetting(app);
event.preventDefault();
return;
}
if (matchHotKey("⌘A", event) && !["INPUT", "TEXTAREA"].includes(target.tagName)) {
event.preventDefault();
return;
}
const matchDock = getAllDocks().find(item => {
if (matchHotKey(item.hotkey, event)) {
getDockByType(item.type).toggleModel(item.type);
event.preventDefault();
return true;
}
});
if (matchDock) {
return;
}
if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.riffCard.custom, event)) {
openCard(app);
if (document.activeElement) {
(document.activeElement as HTMLElement).blur();
}
event.preventDefault();
return;
}
if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.dailyNote.custom, event)) {
newDailyNote(app);
event.stopPropagation();
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.newFile.custom, event)) {
newFile({
app,
useSavePath: true
});
event.preventDefault();
return;
}
// https://github.com/siyuan-note/siyuan/issues/8913#issuecomment-1679720605
const confirmElement = document.querySelector("#confirmDialogConfirmBtn");
if (confirmElement) {
if (event.key === "Enter") {
confirmElement.dispatchEvent(new CustomEvent("click"));
event.preventDefault();
return;
} else if (event.key === "Escape") {
confirmElement.previousElementSibling.previousElementSibling.dispatchEvent(new CustomEvent("click"));
event.preventDefault();
return;
}
}
if (event.key === "Escape" && !event.isComposing) {
const imgPreviewElement = document.querySelector(".protyle-img");
if (imgPreviewElement) {
imgPreviewElement.remove();
return;
}
if (!window.siyuan.menus.menu.element.classList.contains("fn__none")) {
if (window.siyuan.dialogs.length > 0 &&
window.siyuan.menus.menu.element.style.zIndex < (window.siyuan.dialogs[0].element.querySelector(".b3-dialog") as HTMLElement).style.zIndex) {
// 窗口高于菜单时,先关闭窗口,如 av 修改列 icon 时
} else {
window.siyuan.menus.menu.remove();
return;
}
}
// 需放在 menus 后,否则资源列中添加资源会先关闭菜单
// 需放在 dialog 前,否则属性面板中修改日期会先关闭 dialog只剩修改界面
const avElement = document.querySelector(".av__panel");
if (avElement) {
const selectCellElement = document.querySelector(".av__cell--select");
if (selectCellElement) {
focusBlock(hasClosestBlock(selectCellElement) as HTMLElement);
}
avElement.remove();
return;
}
if (window.siyuan.dialogs.length > 0) {
window.siyuan.dialogs[window.siyuan.dialogs.length - 1].destroy();
return;
}
// remove blockpopover
const maxEditLevels: { [key: string]: number } = {oid: 0};
window.siyuan.blockPanels.forEach((item) => {
if ((item.targetElement || typeof item.x === "number") && item.element.getAttribute("data-pin") === "true") {
const level = parseInt(item.element.getAttribute("data-level"));
const oid = item.element.getAttribute("data-oid");
if (maxEditLevels[oid]) {
if (level > maxEditLevels[oid]) {
maxEditLevels[oid] = level;
}
} else {
maxEditLevels[oid] = 1;
}
}
});
let destroyBlock = false;
for (let i = 0; i < window.siyuan.blockPanels.length; i++) {
const item = window.siyuan.blockPanels[i];
if ((item.targetElement || typeof item.x === "number") && item.element.getAttribute("data-pin") === "false") {
item.destroy();
destroyBlock = true;
i--;
}
}
if (destroyBlock) {
return;
}
// 光标在文档树等面板中,按 Esc 回到编辑器中 https://github.com/siyuan-note/siyuan/issues/4289
let range;
if (getSelection().rangeCount > 0) {
range = getSelection().getRangeAt(0);
const protypleElement = hasClosestByClassName(range.startContainer, "protyle-content", true);
if (protypleElement) {
focusByRange(range);
return;
}
} else {
range = document.createRange();
}
const lastBackStack = window.siyuan.backStack[window.siyuan.backStack.length - 1];
if (lastBackStack && lastBackStack.protyle.toolbar.range) {
focusByRange(lastBackStack.protyle.toolbar.range);
} else {
const editor = getAllModels().editor[0];
if (editor) {
focusBlock(editor.editor.protyle.wysiwyg.element.firstElementChild);
}
}
event.preventDefault();
return;
}
if (!isTabWindow && matchHotKey(window.siyuan.config.keymap.general.mainMenu.custom, event)) {
workspaceMenu(app, document.querySelector("#barWorkspace").getBoundingClientRect());
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.goForward.custom, event)) {
goForward(app);
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.goBack.custom, event)) {
goBack(app);
event.preventDefault();
return;
}
// close tab
if (matchHotKey(window.siyuan.config.keymap.general.closeTab.custom, event) && !event.repeat) {
event.preventDefault();
const activeTabElement = document.querySelector(".layout__tab--active");
if (activeTabElement && activeTabElement.getBoundingClientRect().width > 0) {
let type = "";
Array.from(activeTabElement.classList).find(item => {
if (item.startsWith("sy__")) {
type = item.replace("sy__", "");
return true;
}
});
if (type) {
getDockByType(type)?.toggleModel(type, false, true);
}
return;
}
const tab = getActiveTab(false);
if (tab) {
tab.parent.removeTab(tab.id);
}
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.goToTab1.custom, event) && !event.repeat) {
switchTabByIndex(0);
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.goToTab2.custom, event) && !event.repeat) {
switchTabByIndex(1);
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.goToTab3.custom, event) && !event.repeat) {
switchTabByIndex(2);
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.goToTab4.custom, event) && !event.repeat) {
switchTabByIndex(3);
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.goToTab5.custom, event) && !event.repeat) {
switchTabByIndex(4);
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.goToTab6.custom, event) && !event.repeat) {
switchTabByIndex(5);
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.goToTab7.custom, event) && !event.repeat) {
switchTabByIndex(6);
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.goToTab8.custom, event) && !event.repeat) {
switchTabByIndex(7);
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.goToTab9.custom, event) && !event.repeat) {
switchTabByIndex(-1);
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.goToTabNext.custom, event) && !event.repeat) {
switchTabByIndex(-3);
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.goToTabPrev.custom, event) && !event.repeat) {
switchTabByIndex(-2);
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.closeOthers.custom, event) && !event.repeat) {
const tab = getActiveTab(false);
if (tab) {
closeTabByType(tab, "closeOthers");
}
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.closeAll.custom, event) && !event.repeat) {
const tab = getActiveTab(false);
if (tab) {
closeTabByType(tab, "closeAll");
}
event.preventDefault();
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.closeUnmodified.custom, event) && !event.repeat) {
const tab = getActiveTab(false);
if (tab) {
const unmodifiedTabs: Tab[] = [];
tab.parent.children.forEach((item: Tab) => {
const editor = item.model as Editor;
if (!editor || (editor.editor?.protyle && !editor.editor?.protyle.updated)) {
unmodifiedTabs.push(item);
}
});
if (unmodifiedTabs.length > 0) {
closeTabByType(tab, "other", unmodifiedTabs);
}
}
event.preventDefault();
return;
}
if ((matchHotKey(window.siyuan.config.keymap.general.closeLeft.custom, event) || matchHotKey(window.siyuan.config.keymap.general.closeRight.custom, event)) &&
!event.repeat) {
const tab = getActiveTab(false);
if (tab) {
const leftTabs: Tab[] = [];
const rightTabs: Tab[] = [];
let midIndex = -1;
tab.parent.children.forEach((item: Tab, index: number) => {
if (item.id === tab.id) {
midIndex = index;
}
if (midIndex === -1) {
leftTabs.push(item);
} else if (index > midIndex) {
rightTabs.push(item);
}
});
if (matchHotKey(window.siyuan.config.keymap.general.closeLeft.custom, event)) {
if (leftTabs.length > 0) {
closeTabByType(tab, "other", leftTabs);
}
} else {
if (rightTabs.length > 0) {
closeTabByType(tab, "other", rightTabs);
}
}
}
event.preventDefault();
return;
}
if ((
matchHotKey(window.siyuan.config.keymap.general.splitLR.custom, event) ||
matchHotKey(window.siyuan.config.keymap.general.splitMoveR.custom, event) ||
matchHotKey(window.siyuan.config.keymap.general.splitTB.custom, event) ||
matchHotKey(window.siyuan.config.keymap.general.tabToWindow.custom, event) ||
matchHotKey(window.siyuan.config.keymap.general.splitMoveB.custom, event)
) && !event.repeat) {
event.preventDefault();
const tab = getActiveTab(false);
if (tab) {
if (matchHotKey(window.siyuan.config.keymap.general.tabToWindow.custom, event)) {
openNewWindow(tab);
} else if (matchHotKey(window.siyuan.config.keymap.general.splitLR.custom, event)) {
tab.parent.split("lr").addTab(copyTab(app, tab));
} else if (matchHotKey(window.siyuan.config.keymap.general.splitTB.custom, event)) {
tab.parent.split("tb").addTab(copyTab(app, tab));
} else if (tab.parent.children.length > 1) {
const newWnd = tab.parent.split(matchHotKey(window.siyuan.config.keymap.general.splitMoveB.custom, event) ? "tb" : "lr");
newWnd.headersElement.append(tab.headElement);
newWnd.headersElement.parentElement.classList.remove("fn__none");
newWnd.moveTab(tab);
resizeTabs();
}
}
return;
}
if (matchHotKey(window.siyuan.config.keymap.general.stickSearch.custom, event)) {
if (getSelection().rangeCount > 0) {
const range = getSelection().getRangeAt(0);
openGlobalSearch(app, range.toString(), true);
} else {
openGlobalSearch(app, "", true);
}
event.preventDefault();
return;
}
if (editKeydown(app, event)) {
return;
}
// 文件树的操作
if (!isTabWindow && fileTreeKeydown(app, event)) {
return;
}
// 面板的操作
if (!isTabWindow && panelTreeKeydown(app, event)) {
return;
}
let matchCommand = false;
app.plugins.find(item => {
item.commands.find(command => {
if (command.callback &&
!command.fileTreeCallback && !command.editorCallback && !command.dockCallback && !command.globalCallback
&& matchHotKey(command.customHotkey, event)) {
matchCommand = true;
command.callback();
return true;
}
});
if (matchCommand) {
return true;
}
});
if (matchCommand) {
event.stopPropagation();
event.preventDefault();
return true;
}
let searchKey = "";
if (matchHotKey(window.siyuan.config.keymap.general.replace.custom, event)) {
searchKey = Constants.DIALOG_REPLACE;
} else if (!hasClosestByClassName(target, "pdf__outer") && matchHotKey(window.siyuan.config.keymap.general.search.custom, event)) {
searchKey = Constants.DIALOG_SEARCH;
} else if (matchHotKey(window.siyuan.config.keymap.general.globalSearch.custom, event)) {
searchKey = Constants.DIALOG_GLOBALSEARCH;
}
if (searchKey) {
if (getSelection().rangeCount > 0) {
const range = getSelection().getRangeAt(0);
openSearch({
app,
hotkey: searchKey,
key: range.toString(),
});
} else {
openSearch({
app,
hotkey: searchKey,
});
}
event.preventDefault();
return;
}
// https://github.com/siyuan-note/insider/issues/445
if (matchHotKey("⌘S", event)) {
event.preventDefault();
return true;
}
};
export const sendGlobalShortcut = (app: App) => {
/// #if !BROWSER
const hotkeys = [window.siyuan.config.keymap.general.toggleWin.custom];
app.plugins.forEach(plugin => {
plugin.commands.forEach(command => {
if (command.globalCallback) {
hotkeys.push(command.customHotkey);
}
});
});
ipcRenderer.send(Constants.SIYUAN_HOTKEY, {
languages: window.siyuan.languages["_trayMenu"],
hotkeys
});
/// #endif
};