diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2020-01-30 04:37:25 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-01-30 04:37:25 +0900 |
| commit | f6154dc0af1a0d65819e87240f4385f9573095cb (patch) | |
| tree | 699a5ca07d6727b7f8497d4769f25d6d62f94b5a /src/client/scripts/hotkey.ts | |
| parent | Add Event activity-type support (#5785) (diff) | |
| download | misskey-f6154dc0af1a0d65819e87240f4385f9573095cb.tar.gz misskey-f6154dc0af1a0d65819e87240f4385f9573095cb.tar.bz2 misskey-f6154dc0af1a0d65819e87240f4385f9573095cb.zip | |
v12 (#5712)
Co-authored-by: MeiMei <30769358+mei23@users.noreply.github.com>
Co-authored-by: Satsuki Yanagi <17376330+u1-liquid@users.noreply.github.com>
Diffstat (limited to 'src/client/scripts/hotkey.ts')
| -rw-r--r-- | src/client/scripts/hotkey.ts | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/src/client/scripts/hotkey.ts b/src/client/scripts/hotkey.ts new file mode 100644 index 0000000000..ec627ab15b --- /dev/null +++ b/src/client/scripts/hotkey.ts @@ -0,0 +1,106 @@ +import keyCode from './keycode'; +import { concat } from '../../prelude/array'; + +type pattern = { + which: string[]; + ctrl?: boolean; + shift?: boolean; + alt?: boolean; +}; + +type action = { + patterns: pattern[]; + + callback: Function; +}; + +const getKeyMap = keymap => Object.entries(keymap).map(([patterns, callback]): action => { + const result = { + patterns: [], + callback: callback + } as action; + + result.patterns = patterns.split('|').map(part => { + const pattern = { + which: [], + ctrl: false, + alt: false, + shift: false + } as pattern; + + const keys = part.trim().split('+').map(x => x.trim().toLowerCase()); + for (const key of keys) { + switch (key) { + case 'ctrl': pattern.ctrl = true; break; + case 'alt': pattern.alt = true; break; + case 'shift': pattern.shift = true; break; + default: pattern.which = keyCode(key).map(k => k.toLowerCase()); + } + } + + return pattern; + }); + + return result; +}); + +const ignoreElemens = ['input', 'textarea']; + +function match(e: KeyboardEvent, patterns: action['patterns']): boolean { + const key = e.code.toLowerCase(); + return patterns.some(pattern => pattern.which.includes(key) && + pattern.ctrl == e.ctrlKey && + pattern.shift == e.shiftKey && + pattern.alt == e.altKey && + !e.metaKey + ); +} + +export default { + install(Vue) { + Vue.directive('hotkey', { + bind(el, binding) { + el._hotkey_global = binding.modifiers.global === true; + + const actions = getKeyMap(binding.value); + + // flatten + const reservedKeys = concat(actions.map(a => a.patterns)); + + el._misskey_reservedKeys = reservedKeys; + + el._keyHandler = (e: KeyboardEvent) => { + const targetReservedKeys = document.activeElement ? ((document.activeElement as any)._misskey_reservedKeys || []) : []; + if (document.activeElement && ignoreElemens.some(el => document.activeElement.matches(el))) return; + + for (const action of actions) { + const matched = match(e, action.patterns); + + if (matched) { + if (el._hotkey_global && match(e, targetReservedKeys)) return; + + e.preventDefault(); + e.stopPropagation(); + action.callback(e); + break; + } + } + }; + + if (el._hotkey_global) { + document.addEventListener('keydown', el._keyHandler); + } else { + el.addEventListener('keydown', el._keyHandler); + } + }, + + unbind(el) { + if (el._hotkey_global) { + document.removeEventListener('keydown', el._keyHandler); + } else { + el.removeEventListener('keydown', el._keyHandler); + } + } + }); + } +}; |