« get me outta code hell

keybinder.js « src - http-music - Command-line music player + utils (not a server!)
about summary refs log tree commit diff
path: root/src/keybinder.js
blob: 784484c72fd76a25453c87db2fe10258a0978007 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
const splitChars = str => str.split('').map(char => char.charCodeAt(0))

const simpleKeybindings = {
  space: [0x20],
  esc: [0x1b], escape: [0x1b],
  up: [0x1b, ...splitChars('[A')],
  down: [0x1b, ...splitChars('[B')],
  right: [0x1b, ...splitChars('[C')],
  left: [0x1b, ...splitChars('[D')],
  shiftUp: [0x1b, ...splitChars('[1;2A')],
  shiftDown: [0x1b, ...splitChars('[1;2B')],
  shiftRight: [0x1b, ...splitChars('[1;2C')],
  shiftLeft: [0x1b, ...splitChars('[1;2D')],
  delete: [0x7f]
}

module.exports.compileKeybindings = function(bindings, commands) {
  const handlers = bindings.map(binding => {
    const [ keys, command, ...args] = binding

    if (!commands.hasOwnProperty(command)) {
      console.warn('Invalid command', command, 'in keybinding', binding)
      return
    }

    let failed = false

    const bufferParts = keys.map(item => {
      if (typeof item === 'number') {
        return [item]
      } else if (simpleKeybindings.hasOwnProperty(item)) {
        return simpleKeybindings[item]
      } else if (typeof item === 'string' && item.length === 1) {
        return [item.charCodeAt(0)]
      } else {
        // Error
        console.warn('Invalid keybinding part', item, 'in keybinding', bindings)
        failed = true
        return []
      }
    }).reduce((a, b) => a.concat(b), [])

    if (failed) {
      return
    }

    const buffer = Buffer.from(bufferParts)

    return function(inputData) {
      if (buffer.equals(inputData)) {
        commands[command](...args)
        return true
      }
    }
  }).filter(Boolean)

  return function(inputData) {
    for (const handler of handlers) {
      if (handler(inputData)) {
        break
      }
    }
  }
}