Mercurial
comparison .cms/lib/codemirror/src/input/keymap.js @ 0:78edf6b517a0 draft
24.10
author | Coffee CMS <info@coffee-cms.ru> |
---|---|
date | Fri, 11 Oct 2024 22:40:23 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:78edf6b517a0 |
---|---|
1 import { flipCtrlCmd, mac, presto } from "../util/browser.js" | |
2 import { map } from "../util/misc.js" | |
3 | |
4 import { keyNames } from "./keynames.js" | |
5 | |
6 export let keyMap = {} | |
7 | |
8 keyMap.basic = { | |
9 "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", | |
10 "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", | |
11 "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", | |
12 "Tab": "defaultTab", "Shift-Tab": "indentAuto", | |
13 "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", | |
14 "Esc": "singleSelection" | |
15 } | |
16 // Note that the save and find-related commands aren't defined by | |
17 // default. User code or addons can define them. Unknown commands | |
18 // are simply ignored. | |
19 keyMap.pcDefault = { | |
20 "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", | |
21 "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", | |
22 "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", | |
23 "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", | |
24 "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", | |
25 "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", | |
26 "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", | |
27 "fallthrough": "basic" | |
28 } | |
29 // Very basic readline/emacs-style bindings, which are standard on Mac. | |
30 keyMap.emacsy = { | |
31 "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", | |
32 "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", | |
33 "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", | |
34 "Ctrl-T": "transposeChars", "Ctrl-O": "openLine" | |
35 } | |
36 keyMap.macDefault = { | |
37 "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", | |
38 "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", | |
39 "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", | |
40 "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", | |
41 "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", | |
42 "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", | |
43 "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", | |
44 "fallthrough": ["basic", "emacsy"] | |
45 } | |
46 keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault | |
47 | |
48 // KEYMAP DISPATCH | |
49 | |
50 function normalizeKeyName(name) { | |
51 let parts = name.split(/-(?!$)/) | |
52 name = parts[parts.length - 1] | |
53 let alt, ctrl, shift, cmd | |
54 for (let i = 0; i < parts.length - 1; i++) { | |
55 let mod = parts[i] | |
56 if (/^(cmd|meta|m)$/i.test(mod)) cmd = true | |
57 else if (/^a(lt)?$/i.test(mod)) alt = true | |
58 else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true | |
59 else if (/^s(hift)?$/i.test(mod)) shift = true | |
60 else throw new Error("Unrecognized modifier name: " + mod) | |
61 } | |
62 if (alt) name = "Alt-" + name | |
63 if (ctrl) name = "Ctrl-" + name | |
64 if (cmd) name = "Cmd-" + name | |
65 if (shift) name = "Shift-" + name | |
66 return name | |
67 } | |
68 | |
69 // This is a kludge to keep keymaps mostly working as raw objects | |
70 // (backwards compatibility) while at the same time support features | |
71 // like normalization and multi-stroke key bindings. It compiles a | |
72 // new normalized keymap, and then updates the old object to reflect | |
73 // this. | |
74 export function normalizeKeyMap(keymap) { | |
75 let copy = {} | |
76 for (let keyname in keymap) if (keymap.hasOwnProperty(keyname)) { | |
77 let value = keymap[keyname] | |
78 if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue | |
79 if (value == "...") { delete keymap[keyname]; continue } | |
80 | |
81 let keys = map(keyname.split(" "), normalizeKeyName) | |
82 for (let i = 0; i < keys.length; i++) { | |
83 let val, name | |
84 if (i == keys.length - 1) { | |
85 name = keys.join(" ") | |
86 val = value | |
87 } else { | |
88 name = keys.slice(0, i + 1).join(" ") | |
89 val = "..." | |
90 } | |
91 let prev = copy[name] | |
92 if (!prev) copy[name] = val | |
93 else if (prev != val) throw new Error("Inconsistent bindings for " + name) | |
94 } | |
95 delete keymap[keyname] | |
96 } | |
97 for (let prop in copy) keymap[prop] = copy[prop] | |
98 return keymap | |
99 } | |
100 | |
101 export function lookupKey(key, map, handle, context) { | |
102 map = getKeyMap(map) | |
103 let found = map.call ? map.call(key, context) : map[key] | |
104 if (found === false) return "nothing" | |
105 if (found === "...") return "multi" | |
106 if (found != null && handle(found)) return "handled" | |
107 | |
108 if (map.fallthrough) { | |
109 if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") | |
110 return lookupKey(key, map.fallthrough, handle, context) | |
111 for (let i = 0; i < map.fallthrough.length; i++) { | |
112 let result = lookupKey(key, map.fallthrough[i], handle, context) | |
113 if (result) return result | |
114 } | |
115 } | |
116 } | |
117 | |
118 // Modifier key presses don't count as 'real' key presses for the | |
119 // purpose of keymap fallthrough. | |
120 export function isModifierKey(value) { | |
121 let name = typeof value == "string" ? value : keyNames[value.keyCode] | |
122 return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod" | |
123 } | |
124 | |
125 export function addModifierNames(name, event, noShift) { | |
126 let base = name | |
127 if (event.altKey && base != "Alt") name = "Alt-" + name | |
128 if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name | |
129 if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Mod") name = "Cmd-" + name | |
130 if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name | |
131 return name | |
132 } | |
133 | |
134 // Look up the name of a key as indicated by an event object. | |
135 export function keyName(event, noShift) { | |
136 if (presto && event.keyCode == 34 && event["char"]) return false | |
137 let name = keyNames[event.keyCode] | |
138 if (name == null || event.altGraphKey) return false | |
139 // Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause, | |
140 // so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+) | |
141 if (event.keyCode == 3 && event.code) name = event.code | |
142 return addModifierNames(name, event, noShift) | |
143 } | |
144 | |
145 export function getKeyMap(val) { | |
146 return typeof val == "string" ? keyMap[val] : val | |
147 } |