keyboard-js

JavaScript Key Binding Library

Este script no debería instalarse directamente. Es una biblioteca que utilizan otros scripts mediante la meta-directiva de inclusión // @require https://update.greasyfork.org/scripts/23404/149412/keyboard-js.js

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

"use strict"

var Keyboard = (function () {
  function __Keyboard() {
    this.keys = {} // to record the pressed key
    this.register_list = {} // to record the registers(key combos)
    this.state = {} // to record every register matching condition. do you want to get this value?
    this.statistic = {} // the keypress statistic
    this.specialKeyString = {
      "altKey": "Alt",
      "ctrlKey": "Control",
      "metaKey": "Meta",
      "shiftKey": "Shift"
    }
  }
  __Keyboard.prototype.listen = function (keyDown, keyUp) {
    var option = this.option, element = document
    if (option.element && typeof option.element.addEventListener === 'function') {
      element = option.element
    }
    element.addEventListener('keydown', (function (event) {
      this.keydown(event, keyDown)
    }).bind(this), false)
    element.addEventListener('keyup', (function (event) {
      this.keyup(event, keyUp)
    }).bind(this), false)
  }

  __Keyboard.prototype.unlisten = function () {
    // maybe you need callback?
    var option = this.option, element = document
    if (option.element && typeof option.element.removeEventListener === 'function') {
      element = option.element
    }
    element.removeEventListener('keydown', function () { })
    element.removeEventListener('keyup', function () { })
  }

  __Keyboard.prototype.test = function (event) {
    return this.testRegisters(event)
  }

  __Keyboard.prototype.testRegisters = function (event) {
    var register_list = this.register_list
    var register_names = Object.getOwnPropertySymbols(register_list)
    var testKeys = this.testKeys.bind(this)
    var state = {}
    for (var i = 0, len = register_names.length; i < len; i++) {
      var regName = register_names[i]
      var reg = register_list[regName]
      var keylist = reg[0]
      var callback = reg[1]

      // hit the target
      if (testKeys(keylist)) {
        if (callback && typeof callback === 'function') {
          // TODO:
          // Need event object? or context?
          // var __wrapper_callback = (function () {
          //   event.clearKeys = this.clearKeys.bind(this)
          //   // inject the event(the last key) object
          //   callback(event)

          //   // BUG:
          //   // when use `alert` or `confirm`, the event(keyup) of the pressed key will lost.
          //   // so, you will don't know the key is really pressed or not when you are back.
          //   // here code just detects some special keys.
          //   // SO DO NOT USE ALERT OR CONFIRM!
          //   Array.prototype.map.call(Object.keys(this.specialKeyString), ((function (key) {
          //     if (event[key]) this.keys[this.specialKeyString[key]] = true
          //   }).bind(this)))
          // }).bind(this)
          // if (typeof window === 'object' && window.requestAnimationFrame)
          //   window.requestAnimationFrame(__wrapper_callback)
          // else
          //   setTimeout(__wrapper_callback, 16)

          event.clearKeys = this.clearKeys.bind(this)
          callback(event)
        }
        state[regName] = true
        // if match successfully, return directly.
        return state
      }
    }
    return state
  }

  // @param keylist Array(Array) [combo1, combo2, ...]
  __Keyboard.prototype.testKeys = function (keylist) {
    var result = [], state = false
    for (var i = 0, len = keylist.length; i < len; i++) {
      var combo = keylist[i]
      var allPressedkeys = Object.keys(this.keys)
      var nowPressedkeys = []
      var __state = 0 // no state. not true or false

      // collect all pressed key now
      allPressedkeys.forEach((function (value, index) {
        if (this.keys[value]) nowPressedkeys.push(value)
      }).bind(this))

      // DEBUG: print the pressing key message
      // console.log(allPressedkeys, this.keys)
      if (this.option.DEBUG === true) {
        var __printKey = nowPressedkeys.map(function (k, i) {
          if (k === " ") return "Space"
          else return k
        }).join(" ")
        console.log('[' + Date.now() + '] You hit key: %c' + __printKey, 'color: #ea4335; font-size: 16px')
      }

      // compare nowPressedkeys and combo
      // console.log('compare: ', nowPressedkeys, combo)
      if (nowPressedkeys.length !== combo.length) {
        __state = false
      } else {
        for (var j = 0, len2 = combo.length; j < len2; j++) {
          if (nowPressedkeys.indexOf(combo[j]) < 0) {
            // not in the array
            __state = false
            break
          }
        }
        // if j is equal to combo.length, this means that user hit the combo.
        // otherwise, user does't.
        if (j === combo.length && __state !== false) __state = true
      }
      result.push(__state)
    }
    // console.log('> result', result, this.keys)
    result.forEach(function (v, i) {
      if (v === true) state = true
    })
    return state
  }

  __Keyboard.prototype.keydown = function (event, keyDownCallback) {
    var key = event.key, state = {}, rlt = true, map = Array.prototype.map
    this.keys[key] = event.type === 'keydown'
    // this.keys[key] = true
    // the result of test
    // true: hit the target, then prevent the default action, so return true
    // otherwise, don't prevent it, so return false
    state = this.test(event)
    Object.keys(state).forEach(function (regName, i) {
      if (state[regName] === true) rlt = false
    })
    this.state = state
    if (!rlt) {
      event.preventDefault()
      event.stopPropagation()
      // event.stopImmediatePropagation()
    }
    // console.log(rlt)
    // statistic
    this.collect(event.key, event.type, event.timeStamp)
    if (typeof keyDownCallback === 'function') keyDownCallback(event)
    return rlt
  }

  __Keyboard.prototype.keyup = function (event, keyUpCallback) {
    var key = event.key
    this.keys[key] = false
    // statistic
    this.collect(event.key, event.type, event.timeStamp)
    if (typeof keyUpCallback === 'function') keyUpCallback(event)
    return true
  }

  __Keyboard.prototype.collect = function (key, type, timeStamp) {
    // lazy calculate
    var target = this.statistic[key]
    var _timeStamp = !!window.CustomEvent ? new CustomEvent('test').timeStamp : document.createEvent('KeyboardEvent').timeStamp
    if (typeof target === 'undefined')
      target = this.statistic[key] = {count: 0, total: 0, average: 0}
    if (type === 'keydown') {
      target.downTimeStamp = timeStamp || _timeStamp
    } else if (type === 'keyup') {
      target.count = target.count + 1
      target.upTimeStamp = timeStamp || _timeStamp
      target.total = (target.upTimeStamp - target.downTimeStamp) + target.total
      target.total = +target.total.toFixed(2) || 0 // if incorrect, set 0
      target.average = target.total / target.count
    }
  }

  __Keyboard.prototype.register = function (name, callback/*, keylist*/) {
    if (typeof name !== 'string') throw new Error('[from keyboard-js] Please input a register name.')
    var sym
    if (typeof Symbol !== 'undefined') sym = Symbol.for(name)
    else sym = name
    if (this.register_list[sym]) throw new Error('[from keyboard-js] The Register[' + name + '] has existed!')
    var keylist = Array.prototype.slice.call(arguments, 2)
    if (!(keylist[0] instanceof Array)) keylist = [keylist] // init [combo1:Array, combo2:Array, ....]
    this.register_list[sym] = [keylist, callback]
  }

  __Keyboard.prototype.clearRegister = function (name) {
    delete this.register_list[name]
  }
  __Keyboard.prototype.clearRegisterAll = function () {
    this.register_list = {}
  }
  __Keyboard.prototype.clearKeys = function () {
    this.keys = {}
  }
  var k = new __Keyboard()

  var __instance = {
    start: function (keyDown, keyUp) { k.listen(keyDown, keyUp) },
    end: function () { k.unlisten(); k.clearRegisterAll(); k.clearKeys(); },
    register: function () { k.register.apply(k, arguments) },
    unregister: function () { k.clearRegister.apply(k, arguments) },
    getStatistic: function () { return k.statistic },
    // for test
    __keydown: function () { k.keydown.apply(k, arguments) },
    __keyup: function () { k.keyup.apply(k, arguments) }
  }

  return function (o) {
    k.option = o || {}
    if (typeof window === 'object') window.addEventListener('focus', function () {
      k.keys = {}
    }, false)
    // window.addEventListener('blur', function () {
    //     k.keys = {}
    // }, false)
    return __instance
  }
})()

if (typeof exports !== "undefined") {
  exports.Keyboard = Keyboard
} else if (typeof define === 'function') {
  define("Keyboard", [], function () {
    return Keyboard
  })
} else {
  if (window.Keyboard === undefined) window.Keyboard = Keyboard
  else {
    throw new Error('Library Keyboard has existed! Loaded failed.')
  }
}