A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1import {isMac, isNotCtrl, isOnlyMeta} from "./compatibility";
2import {Constants} from "../../constants";
3
4// 是否匹配辅助键 ⌃⌥⇧⌘
5export const matchAuxiliaryHotKey = (hotKey: string, event: KeyboardEvent) => {
6 if (hotKey.includes("⌃")) {
7 if (!event.ctrlKey) {
8 return false;
9 }
10 } else {
11 if (isMac() ? event.ctrlKey : (hotKey.includes("⌘") ? !event.ctrlKey : event.ctrlKey)) {
12 return false;
13 }
14 }
15 if (hotKey.includes("⌥")) {
16 if (!event.altKey) {
17 return false;
18 }
19 } else {
20 if (event.altKey) {
21 return false;
22 }
23 }
24 if (hotKey.includes("⇧")) {
25 if (!event.shiftKey) {
26 return false;
27 }
28 } else {
29 if (event.shiftKey) {
30 return false;
31 }
32 }
33 if (hotKey.includes("⌘")) {
34 if (isMac() ? !event.metaKey : !event.ctrlKey) {
35 return false;
36 }
37 } else {
38 if (isMac() ? event.metaKey : (hotKey.includes("⌃") ? !event.ctrlKey : event.ctrlKey)) {
39 return false;
40 }
41 }
42 return true;
43};
44
45const replaceDirect = (hotKey: string, keyCode: string) => {
46 const hotKeys = hotKey.replace(keyCode, Constants.ZWSP).split("");
47 hotKeys.forEach((item, index) => {
48 if (item === Constants.ZWSP) {
49 hotKeys[index] = keyCode;
50 }
51 });
52 return hotKeys;
53};
54
55export const matchHotKey = (hotKey: string, event: KeyboardEvent) => {
56 if (!hotKey) {
57 return false;
58 }
59
60 // https://github.com/siyuan-note/siyuan/issues/9770
61 if (hotKey.startsWith("⌃") && !isMac()) {
62 if (hotKey === "⌃D") {
63 // https://github.com/siyuan-note/siyuan/issues/9841
64 return false;
65 }
66 hotKey = hotKey.replace("⌘", "").replace("⌃", "⌘")
67 .replace("⌘⇧", "⇧⌘")
68 .replace("⌘⌥⇧", "⌥⇧⌘")
69 .replace("⌘⌥", "⌥⌘");
70 }
71
72 // []
73 if (hotKey.indexOf("⇧") === -1 && hotKey.indexOf("⌘") === -1 && hotKey.indexOf("⌥") === -1 && hotKey.indexOf("⌃") === -1) {
74 if (isNotCtrl(event) && !event.altKey && !event.shiftKey && hotKey === Constants.KEYCODELIST[event.keyCode]) {
75 return true;
76 }
77 return false;
78 }
79
80 let hotKeys = hotKey.split("");
81 if (hotKey.indexOf("F") > -1) {
82 hotKeys.forEach((item, index) => {
83 if (item === "F") {
84 // F1-F12
85 hotKeys[index] = "F" + hotKeys.splice(index + 1, 1);
86 if (hotKeys[index + 1]) {
87 hotKeys[index + 1] += hotKeys.splice(index + 1, 1);
88 }
89 }
90 });
91 } else if (hotKey.indexOf("PageUp") > -1) {
92 hotKeys = replaceDirect(hotKey, "PageUp");
93 } else if (hotKey.indexOf("PageDown") > -1) {
94 hotKeys = replaceDirect(hotKey, "PageDown");
95 } else if (hotKey.indexOf("Home") > -1) {
96 hotKeys = replaceDirect(hotKey, "Home");
97 } else if (hotKey.indexOf("End") > -1) {
98 hotKeys = replaceDirect(hotKey, "End");
99 }
100
101 // 是否匹配 ⇧[]
102 if (hotKey.startsWith("⇧") && hotKeys.length === 2) {
103 if (isNotCtrl(event) && !event.altKey && event.shiftKey && hotKeys[1] === Constants.KEYCODELIST[event.keyCode]) {
104 return true;
105 }
106 return false;
107 }
108
109 if (hotKey.startsWith("⌥")) {
110 let keyCode = hotKeys.length === 3 ? hotKeys[2] : hotKeys[1];
111 if (hotKeys.length === 4) {
112 keyCode = hotKeys[3];
113 }
114 const isMatchKey = keyCode === Constants.KEYCODELIST[event.keyCode];
115 // 是否匹配 ⌥[] / ⌥⌘[]
116 if (isMatchKey && event.altKey && !event.shiftKey && hotKeys.length < 4 &&
117 (hotKeys.length === 3 ? (isOnlyMeta(event) && hotKey.startsWith("⌥⌘")) : isNotCtrl(event))) {
118 return true;
119 }
120 // ⌥⇧⌘[]
121 if (isMatchKey && hotKey.startsWith("⌥⇧⌘") && hotKeys.length === 4 &&
122 event.altKey && event.shiftKey && isOnlyMeta(event)) {
123 return true;
124 }
125 // ⌥⇧[]
126 if (isMatchKey && hotKey.startsWith("⌥⇧") && hotKeys.length === 3 &&
127 event.altKey && event.shiftKey && isNotCtrl(event)) {
128 return true;
129 }
130 return false;
131 }
132
133 // 是否匹配 ⌃[] / ⌃⌘[] / ⌃⌥[] / ⌃⇧[]/ ⌃⌥⇧[]
134 if (hotKey.startsWith("⌃")) {
135 if (!isMac()) {
136 return false;
137 }
138 let keyCode = hotKeys.length === 3 ? hotKeys[2] : hotKeys[1];
139 if (hotKeys.length === 4) {
140 keyCode = hotKeys[3];
141 } else if (hotKeys.length === 5) {
142 keyCode = hotKeys[4];
143 }
144
145 const isMatchKey = keyCode === Constants.KEYCODELIST[event.keyCode];
146 // 是否匹配 ⌃[] / ⌃⌘[]
147 if (isMatchKey && event.ctrlKey && !event.altKey && !event.shiftKey && hotKeys.length < 4 &&
148 (hotKeys.length === 3 ? (event.metaKey && hotKey.startsWith("⌃⌘")) : !event.metaKey)) {
149 return true;
150 }
151 // ⌃⇧[]
152 if (isMatchKey && hotKey.startsWith("⌃⇧") && hotKeys.length === 3 &&
153 event.ctrlKey && !event.altKey && event.shiftKey && !event.metaKey) {
154 return true;
155 }
156 // ⌃⌥[]
157 if (isMatchKey && hotKey.startsWith("⌃⌥") && hotKeys.length === 3 &&
158 event.ctrlKey && event.altKey && !event.shiftKey && !event.metaKey) {
159 return true;
160 }
161 // ⌃⌥⇧[] / ⌃⌥⌘[] / ⌃⇧⌘[]
162 if (isMatchKey && hotKeys.length === 4 && event.ctrlKey &&
163 (
164 (hotKey.startsWith("⌃⌥⇧") && event.shiftKey && !event.metaKey && event.altKey) ||
165 (hotKey.startsWith("⌃⌥⌘") && !event.shiftKey && event.metaKey && event.altKey) ||
166 (hotKey.startsWith("⌃⇧⌘") && event.shiftKey && event.metaKey && !event.altKey)
167 )
168 ) {
169 return true;
170 }
171
172 // ⌃⌥⇧⌘[]
173 if (isMatchKey && hotKeys.length === 5 && event.ctrlKey && event.shiftKey && event.metaKey && event.altKey) {
174 return true;
175 }
176 return false;
177 }
178
179 // 是否匹配 ⇧⌘[] / ⌘[]
180 const hasShift = hotKeys.length > 2 && (hotKeys[0] === "⇧");
181 if (isOnlyMeta(event) && !event.altKey && ((!hasShift && !event.shiftKey) || (hasShift && event.shiftKey))) {
182 return (hasShift ? hotKeys[2] : hotKeys[1]) === Constants.KEYCODELIST[event.keyCode];
183 }
184 return false;
185};
186
187export const isIncludesHotKey = (hotKey: string) => {
188 let isInclude = false;
189 Object.keys(window.siyuan.config.keymap).find(key => {
190 const item = window.siyuan.config.keymap[key as "editor"];
191 Object.keys(item).find(key2 => {
192 const item2 = item[key2 as "general"];
193 if (typeof item2.custom === "string") {
194 if (item2.custom === hotKey) {
195 isInclude = true;
196 return true;
197 }
198 } else {
199 Object.keys(item2).forEach(key3 => {
200 const item3: Config.IKey = item2[key3];
201 if (item3.custom === hotKey) {
202 isInclude = true;
203 return true;
204 }
205 });
206 if (isInclude) {
207 return true;
208 }
209 }
210 });
211
212 if (isInclude) {
213 return true;
214 }
215 });
216
217 return isInclude;
218};
219
220export const updateControlAlt = () => {
221 if (!window.siyuan.config.keymap.general) {
222 return;
223 }
224 Object.keys(window.siyuan.config.keymap.general).forEach(key => {
225 if (["fileTree", "outline", "bookmark", "tag", "dailyNote", "inbox", "backlinks",
226 "graphView", "globalGraph", "riffCard"].includes(key)) {
227 if (navigator.platform.toUpperCase().indexOf("MAC") > -1) {
228 window.siyuan.config.keymap.general[key].default = window.siyuan.config.keymap.general[key].default.replace("⌥", "⌃");
229 if (window.siyuan.config.keymap.general[key].default === window.siyuan.config.keymap.general[key].custom) {
230 window.siyuan.config.keymap.general[key].custom = window.siyuan.config.keymap.general[key].default.replace("⌥", "⌃");
231 }
232 } else {
233 window.siyuan.config.keymap.general[key].default = window.siyuan.config.keymap.general[key].default.replace("⌃", "⌥");
234 if (window.siyuan.config.keymap.general[key].default === window.siyuan.config.keymap.general[key].custom) {
235 window.siyuan.config.keymap.general[key].custom = window.siyuan.config.keymap.general[key].default.replace("⌃", "⌥");
236 }
237 }
238 }
239 });
240};