From b185ff5f1d0b6aba85f11a25cb1d986616848aac Mon Sep 17 00:00:00 2001 From: dstoc <539597+dstoc@users.noreply.github.com> Date: Sat, 16 Nov 2024 19:34:46 +1100 Subject: [PATCH] feat: More sophisticated mapping of mac keys --- src/editor.ts | 33 ++++++++++++++++----------------- src/keyboard.ts | 36 ++++++++++++++++++++++++++++++++++-- src/pkmapp.ts | 5 +++-- 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/editor.ts b/src/editor.ts index 88142a8..9aff17b 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -73,7 +73,7 @@ import {Focus} from './markdown/view-model-ops.js'; import {findOpenCreateBundle} from './commands/find-open-create.js'; import {CommandContext} from './commands/context.js'; import {sigprop} from './signal-utils.js'; -import {platformModifier} from './keyboard.js'; +import {normalizeKeys} from './keyboard.js'; export interface EditorNavigation { kind: 'navigate' | 'replace'; @@ -378,24 +378,23 @@ export class Editor extends LitElement { const { detail: {inline, node, keyboardEvent}, } = event; + const keyDown = normalizeKeys(keyboardEvent); const hostContext = cast(inline.hostContext); assert(inline.node); if (this.autocomplete.onInlineKeyDown(event)) { return; } else if ( - ['ArrowUp', 'ArrowLeft', 'ArrowDown', 'ArrowRight'].includes( - keyboardEvent.key, - ) + ['ArrowUp', 'ArrowLeft', 'ArrowDown', 'ArrowRight'].includes(keyDown.key) ) { keyboardEvent.preventDefault(); - const direction = ['ArrowUp', 'ArrowLeft'].includes(keyboardEvent.key) + const direction = ['ArrowUp', 'ArrowLeft'].includes(keyDown.key) ? 'backward' : 'forward'; - const alter = keyboardEvent.shiftKey ? 'extend' : 'move'; - const granularity = ['ArrowUp', 'ArrowDown'].includes(keyboardEvent.key) + const alter = keyDown.shiftKey ? 'extend' : 'move'; + const granularity = ['ArrowUp', 'ArrowDown'].includes(keyDown.key) ? 'line' - : platformModifier(keyboardEvent) + : keyDown.ctrlKey ? 'word' : 'character'; const result = hostContext.hasSelection @@ -456,16 +455,16 @@ export class Editor extends LitElement { } } } - } else if (keyboardEvent.key === 'Tab') { + } else if (keyDown.key === 'Tab') { keyboardEvent.preventDefault(); - const mode = keyboardEvent.shiftKey ? 'unindent' : 'indent'; + const mode = keyDown.shiftKey ? 'unindent' : 'indent'; const blockTarget = getBlockSelectionTarget(inline); if (blockTarget) { this.runEditAction(blockTarget, editBlockSelectionIndent, mode); } else { this.runEditAction(inline, editInlineIndent, mode); } - } else if (keyboardEvent.key === 'z' && platformModifier(keyboardEvent)) { + } else if (keyDown.key === 'z' && keyDown.ctrlKey) { if (!hostContext.root) return; event.preventDefault(); const focus = hostContext.root[viewModel].tree.undo(hostContext.root); @@ -478,7 +477,7 @@ export class Editor extends LitElement { hostContext.focusOffset = focus.offset; focus.node[viewModel].renderSignal.value++; } - } else if (keyboardEvent.key === 'y' && platformModifier(keyboardEvent)) { + } else if (keyDown.key === 'y' && keyDown.ctrlKey) { if (!hostContext.root) return; event.preventDefault(); const focus = hostContext.root[viewModel].tree.redo(hostContext.root); @@ -491,7 +490,7 @@ export class Editor extends LitElement { hostContext.focusOffset = focus.offset; focus.node[viewModel].renderSignal.value++; } - } else if (keyboardEvent.key === 'a' && platformModifier(keyboardEvent)) { + } else if (keyDown.key === 'a' && keyDown.ctrlKey) { this.autocomplete.abort(); const {hostContext: selectedHostContext} = getBlockSelectionTarget(inline) ?? {}; @@ -510,12 +509,12 @@ export class Editor extends LitElement { hostContext.setSelection(node, node); } } - } else if (keyboardEvent.key === 'c' && platformModifier(keyboardEvent)) { + } else if (keyDown.key === 'c' && keyDown.ctrlKey) { const {hostContext} = getBlockSelectionTarget(inline) ?? {}; if (!hostContext) return; keyboardEvent.preventDefault(); noAwait(copyMarkdownToClipboard(serializeSelection(hostContext))); - } else if (keyboardEvent.key === 'x' && platformModifier(keyboardEvent)) { + } else if (keyDown.key === 'x' && keyDown.ctrlKey) { const selectionTarget = getBlockSelectionTarget(inline); if (!selectionTarget?.hostContext) return; keyboardEvent.preventDefault(); @@ -525,9 +524,9 @@ export class Editor extends LitElement { ), ); this.runEditAction(selectionTarget, removeSelectedNodes); - } else if (keyboardEvent.key === 'Escape') { + } else if (keyDown.key === 'Escape') { hostContext.clearSelection(); - } else if (keyboardEvent.key === 'Backspace') { + } else if (keyDown.key === 'Backspace') { const selectionTarget = getBlockSelectionTarget(inline); if (!selectionTarget?.hostContext) return; keyboardEvent.preventDefault(); diff --git a/src/keyboard.ts b/src/keyboard.ts index 745eb89..d4442f1 100644 --- a/src/keyboard.ts +++ b/src/keyboard.ts @@ -1,4 +1,36 @@ const isMac = /Mac|iPhone/i.test(navigator.platform); -export function platformModifier(e: KeyboardEvent) { - return isMac ? e.metaKey : e.ctrlKey; + +export function normalizeKeys({ + key, + shiftKey, + ctrlKey, + altKey, + metaKey, +}: KeyboardEvent) { + if (isMac) { + if (altKey && !ctrlKey) { + if (['ArrowLeft', 'ArrowRight', 'Backpace', 'Delete'].includes(key)) { + altKey = false; + ctrlKey = true; + } + } else if (metaKey && !ctrlKey) { + if (key === 'ArrowLeft') { + key = 'Home'; + metaKey = false; + } else if (key === 'ArrowRight') { + key = 'End'; + metaKey = false; + } else { + metaKey = true; + ctrlKey = false; + } + } + } + return { + key, + ctrlKey, + shiftKey, + altKey, + metaKey, + }; } diff --git a/src/pkmapp.ts b/src/pkmapp.ts index 60bdfac..4daf45a 100644 --- a/src/pkmapp.ts +++ b/src/pkmapp.ts @@ -47,7 +47,7 @@ import {Components, ComponentsBuilder} from './components.js'; import {Backup} from './backup.js'; import {ConfigStore} from './config-store.js'; import {BackLinks} from './backlinks.js'; -import {platformModifier} from './keyboard.js'; +import {normalizeKeys} from './keyboard.js'; export function injectStyles() { document.adoptedStyleSheets = [...styles]; @@ -97,7 +97,8 @@ export abstract class PkmAppBase extends LitElement { constructor() { super(); document.addEventListener('keydown', (e) => { - if (e.key === 'p' && platformModifier(e)) { + const {key, ctrlKey} = normalizeKeys(e); + if (key === 'p' && ctrlKey) { e.preventDefault(); this.onCommands({detail: undefined}); }