diff options
| author | Shin'ya Ueoka <ueokande@i-beam.org> | 2019-05-18 21:43:56 +0900 | 
|---|---|---|
| committer | Shin'ya Ueoka <ueokande@i-beam.org> | 2019-05-18 21:43:56 +0900 | 
| commit | a5518dce3d101cb1cb65724b82079f66f20c80c8 (patch) | |
| tree | 79537b86e4a7bf231e8801c9c6bf2aeb94450343 /src/content/domains | |
| parent | 2ec912c262b51fe9523ebf74d5062d0b9bbdab71 (diff) | |
Define Key and KeySequence
Diffstat (limited to 'src/content/domains')
| -rw-r--r-- | src/content/domains/Key.ts | 74 | ||||
| -rw-r--r-- | src/content/domains/KeySequence.ts | 64 | 
2 files changed, 138 insertions, 0 deletions
| diff --git a/src/content/domains/Key.ts b/src/content/domains/Key.ts new file mode 100644 index 0000000..fbbb4bb --- /dev/null +++ b/src/content/domains/Key.ts @@ -0,0 +1,74 @@ +export default interface Key { +  key: string; +  shiftKey?: boolean; +  ctrlKey?: boolean; +  altKey?: boolean; +  metaKey?: boolean; + +  // eslint-disable-next-line semi +} + +const modifiedKeyName = (name: string): string => { +  if (name === ' ') { +    return 'Space'; +  } +  if (name.length === 1) { +    return name; +  } else if (name === 'Escape') { +    return 'Esc'; +  } +  return name; +}; + +export const fromKeyboardEvent = (e: KeyboardEvent): Key => { +  let key = modifiedKeyName(e.key); +  let shift = e.shiftKey; +  if (key.length === 1 && key.toUpperCase() === key.toLowerCase()) { +    // make shift false for symbols to enable key bindings by symbold keys. +    // But this limits key bindings by symbol keys with Shift (such as Shift+$>. +    shift = false; +  } + +  return { +    key: modifiedKeyName(e.key), +    shiftKey: shift, +    ctrlKey: e.ctrlKey, +    altKey: e.altKey, +    metaKey: e.metaKey, +  }; +}; + +export const fromMapKey = (key: string): Key => { +  if (key.startsWith('<') && key.endsWith('>')) { +    let inner = key.slice(1, -1); +    let shift = inner.includes('S-'); +    let base = inner.slice(inner.lastIndexOf('-') + 1); +    if (shift && base.length === 1) { +      base = base.toUpperCase(); +    } else if (!shift && base.length === 1) { +      base = base.toLowerCase(); +    } +    return { +      key: base, +      shiftKey: inner.includes('S-'), +      ctrlKey: inner.includes('C-'), +      altKey: inner.includes('A-'), +      metaKey: inner.includes('M-'), +    }; +  } +  return { +    key: key, +    shiftKey: key.toLowerCase() !== key, +    ctrlKey: false, +    altKey: false, +    metaKey: false, +  }; +}; + +export const equals = (e1: Key, e2: Key): boolean => { +  return e1.key === e2.key && +    e1.ctrlKey === e2.ctrlKey && +    e1.metaKey === e2.metaKey && +    e1.altKey === e2.altKey && +    e1.shiftKey === e2.shiftKey; +}; diff --git a/src/content/domains/KeySequence.ts b/src/content/domains/KeySequence.ts new file mode 100644 index 0000000..6a05c2f --- /dev/null +++ b/src/content/domains/KeySequence.ts @@ -0,0 +1,64 @@ +import Key, * as keyUtils from './Key'; + +export default class KeySequence { +  private keys: Key[]; + +  private constructor(keys: Key[]) { +    this.keys = keys; +  } + +  static from(keys: Key[]): KeySequence { +    return new KeySequence(keys); +  } + +  push(key: Key): number { +    return this.keys.push(key); +  } + +  length(): number { +    return this.keys.length; +  } + +  startsWith(o: KeySequence): boolean { +    if (this.keys.length < o.keys.length) { +      return false; +    } +    for (let i = 0; i < o.keys.length; ++i) { +      if (!keyUtils.equals(this.keys[i], o.keys[i])) { +        return false; +      } +    } +    return true; +  } + +  getKeyArray(): Key[] { +    return this.keys; +  } +} + +export const fromMapKeys = (keys: string): KeySequence => { +  const fromMapKeysRecursive = ( +    remainings: string, mappedKeys: Key[], +  ): Key[] => { +    if (remainings.length === 0) { +      return mappedKeys; +    } + +    let nextPos = 1; +    if (remainings.startsWith('<')) { +      let ltPos = remainings.indexOf('>'); +      if (ltPos > 0) { +        nextPos = ltPos + 1; +      } +    } + +    return fromMapKeysRecursive( +      remainings.slice(nextPos), +      mappedKeys.concat([keyUtils.fromMapKey(remainings.slice(0, nextPos))]) +    ); +  }; + +  let data = fromMapKeysRecursive(keys, []); +  return KeySequence.from(data); +}; + | 
