generated at
JSのkeyをVim key codeに変換するscript
{key: 'A', shiftKey: true, ctrlKey: true} などを <C-A> に変換するscript

script.js
import {mouseCodes, normalKeys, specialKeys} from './characters.js';

javascriptVim
< \< になる
\ \\ になる
script.js
export function js2vim({key, button, ctrlKey, shiftKey, altKey}) { let code = ''; // マウスクリックの場合 if (button) { code = button < 3 ? mouseCodes[button] : 'otherMouse'; // キーボード入力の場合 } else if (key) { // Processは無視 if (key === 'Process') return undefined; switch(key) { // 修飾キーのみの場合は無視 case 'Shift': case 'Control': case 'Alt': return undefined; default: if (!(key in specialKeys) && !(key in normalKeys)) { const json = {key, ctrlKey, shiftKey, altKey}; throw Error(`Invalid key name: ${JSON.stringify(json)}`); } code = specialKeys[key] ?? normalKeys[key]; break; } } else { return undefined; } // 修飾キーをつける // どれか一つのmeta keyしか有効にしない if (altKey) return `<A-${code}>`; if (ctrlKey) return `<C-${code}>`; // Shift keyは印字可能キー以外につける if (shiftKey && !(key in normalKeys)) return `<S-${code}>`; return (key in specialKeys) ? `<${code}>` : code; }

Vimjavascript
script.js
const rMouseCodes = reverse(mouseCodes); const rNormalKeys = reverse(normalKeys); const rSpecialKeys = reverse(specialKeys); export function vim2js(keyString) { const {meta, key} = parse(keyString); if (key in rMouseCodes) { const button = rMouseCodes[key]; switch (meta) { case 'A': return {button, altKey: meta}; case 'S': return {button, shiftKey: meta}; case 'C': return {button, ctrlKey: meta}; } } const newKey = rNormalKeys[key] ?? rNormalKeys[key]; if (newKey === undefined) throw Error(`Invalid key notation: ${JSON.stringify({notation: keyString, meta, key})}`); switch (meta) { case 'A': return {key: newKey, altKey: meta}; case 'S': return {key: newKey, shiftKey: meta}; case 'C': return {key: newKey, ctrlKey: meta}; } } // keyの解析 function parse(keyString) { if (/^<[ASC]-(?:>|[^>]+)>$/.test(keyString)) { const [meta, key] = keyString.match(/^<([ASC])-(>|[^>]+)>$/).slice(1); return {meta, key}; } if (/^<[^>]>$/.test(keyString)) { return {key: keyString.slice(1, -1)}; } return {key: keyString}; } function reverse(object) { return Object.fromEntries(Object.entries(object).map(pair => pair.reverse())); }

Vim key notationの対応表
characters.js
const range = (i, j) => [...Array(j + 1).keys()].slice(i, j + 1); // <>無しのキー export const normalKeys = Object.fromEntries( range('!'.charCodeAt(0), '~'.charCodeAt(0)) .flatMap(code => { const key = String.fromCodePoint(code); if (key === '<') return [['<', '\\<']]; if (key === '\\') return [['\\', '\\\\']]; return [[key, key]]; }) ); // <>ありのキー export const specialKeys = { Backspace: 'BS', Enter: 'CR', Delete: 'Del', Escape: 'Esc', ' ': 'Space', ArrowLeft: 'Left', ArrowUp: 'Up', ArrowRight: 'Right', ArrowDown: 'Down', ...Object.fromEntries([ 'Tab', 'PageUp', 'PageDown', 'End', 'Home', ...range(1, 12).map(i => `F${i + 1}`), ].map(key => [key, key])), }; export const keyboardCodes = {...specialKeys, ...normalKeys}; export const mouseCodes = { 0: 'LeftMouse', 1: 'MiddleMouse', 2: 'RightMouse', };

test code
js
import('/api/code/programming-notes/JSのkeyをVim_key_codeに変換するscript/test1.js');
test1.js
import {js2vim} from './script.js'; const chars = '!"#$%&\'()~=~|QWERTYUIOP`{ASDFGHJKL+*}ZXCVBNM<>?_qwertyuiop@[asdfghjkl;:]zxcvbnm,./\\-^'; console.log(chars.split('').map(key => { const code = js2vim({key, shiftKey: true}); return {code, judge: code === key}; })); console.log(chars.split('').map(key => { const code = js2vim({key, altKey: true, ctrlKey: true}); return {code, judge: code === `<A-${key}>`}; })); console.log(chars.split('').map(key => { const code = js2vim({key, ctrlKey: true}); return {code, judge: code === `<C-${key}>`}; }));


JavaScript