【问题标题】:Can jQuery .keypress() detect more than one key at the same time?jQuery .keypress() 可以同时检测多个键吗?
【发布时间】:2011-06-24 16:11:03
【问题描述】:

有没有办法让 jQuery 检测到同时按下了多个键?

是否有任何替代方法可以检测同时按下两个键?

【问题讨论】:

    标签: javascript jquery


    【解决方案1】:

    为了检测多个键被按下,使用keydownkeyup 事件。

    var keys = {};
    
    $(document).keydown(function (e) {
        keys[e.which] = true;
    });
    
    $(document).keyup(function (e) {
        delete keys[e.which];
    });
    

    我在这里做了一个演示:http://jsfiddle.net/gFcuU/。这很有趣,虽然我注意到我的键盘最多只能检测 6 个键。

    【讨论】:

    • 不错的脚本,当它们的字符代码相距很远(2 个或更多差异)时,我最多只能同时获得 6 个键。附言。为什么要删除密钥而不是将其设置为 false?
    • @jerone 我想我不希望对象与所有键的历史记录混淆,它会在printKeys 循环中节省一些迭代。但在实践中,你是对的,这是一个很小的差异。
    • 我也可以做大约 7 个键,但是对于我想要的(箭头键),有一些组合允许 3 或 2,但从不允许 4...有趣
    • @ajax333221 这通常是硬件问题 - 由于您的键盘接线方式。不同的键盘会有不同的表现。
    • 参见:jsfiddle.net/gFcuU/524 - 尝试 CTRL + C 一些文本。之后,“向下键”将保持为 1,直到您分别按下/释放 CTRL 和 C。我们怎样才能避免这种情况?
    【解决方案2】:

    这取决于。对于“普通”键,这意味着非 ShiftCtrlALT、(CMD),答案否,事件处理程序将一个接一个地在队列中捕获/触发。

    对于我上面提到的修饰键,事件对象上有一个属性。

    例子:

    $(document).bind('keypress', function(event) {
        if( event.which === 65 && event.shiftKey ) {
            alert('you pressed SHIFT+A');
        }
    });
    

    Jsfiddle demo.

    其他属性是:

    • event.ctrlKey
    • event.altKey
    • event.metaKey

    【讨论】:

    • 出于实际原因,它是 windows/command 键(但是..en.wikipedia.org/wiki/Meta_key
    • @Jacob,我猜是 windows/mac 键?来自 w3:“在某些平台上,此键可能会映射到替代键名称。”
    • @Box9:不,在我的 Mac 上,metaKey 设置为 true,用于 alt、shift、ctrl 和 cmd。值得注意的是keypress 不会为CMD 触发。但是对于keydown,例如
    • 其实这很奇怪,metaKey 仅适用于我在 Chrome 中的 mac 上的 Cmd。
    • @Box9:在 FF 3.6.x 上进行测试。 metaKey 适用于 ctrlcmd
    【解决方案3】:

    如果您只想在连续按下多个键时触发处理程序,请尝试以下操作:

    jQuery.multipress = function (keys, handler) {
        'use strict';
    
        if (keys.length === 0) {
            return;
        }
    
        var down = {};
        jQuery(document).keydown(function (event) {
            down[event.keyCode] = true;
        }).keyup(function (event) {
            // Copy keys array, build array of pressed keys
            var remaining = keys.slice(0),
                pressed = Object.keys(down).map(function (num) { return parseInt(num, 10); }),
                indexOfKey;
            // Remove pressedKeys from remainingKeys
            jQuery.each(pressed, function (i, key) {
                if (down[key] === true) {
                    down[key] = false;
                    indexOfKey = remaining.indexOf(key);
                    if (indexOfKey > -1) {
                        remaining.splice(indexOfKey, 1);
                    }
                }
            });
            // If we hit all the keys, fire off handler
            if (remaining.length === 0) {
                handler(event);
            }
        });
    };
    

    例如,要在 s-t 上开火,

    jQuery.multipress([83, 84], function () { alert('You pressed s-t'); })
    

    【讨论】:

    • 肯定有更好的解决方案,但如果您只是添加按键来触发调试代码等,最好不要添加其他依赖项。
    【解决方案4】:

    不。 keypress 将针对每个按下的单独键触发 - 除了 CTRL、ALT 和 SHIFT 等修饰键之外,您可以将它们与其他键组合,只要它只是一个其他键。

    【讨论】:

      【解决方案5】:

      这是一个基于 jQuery 的解决方案 Maciej 的回答https://stackoverflow.com/a/21522329/

      // the array to add pressed keys to
      var keys = [];
      // listen for which key is pressed
      document.addEventListener('keydown', (event) => {
          if ($.inArray(event.keyCode, keys) == -1) {
              keys.push(event.keyCode);
          }
          console.log('keys array after pressed = ' + keys);
      });
      // listen for which key is unpressed
      document.addEventListener('keyup', (event) => {
          // the key to remove
          var removeKey = event.keyCode;
        // remove it
          keys = $.grep(keys, function(value) {
              return value != removeKey;
          });
          console.log('keys array after unpress = ' + keys);
      });
      // assign key number to a recognizable value name
      var w = 87;
      var d = 68;
      var s = 83;
      var a = 65;
      // determine which keys are pressed
      document.addEventListener('keydown', (event) => {
        if ($.inArray(w, keys) != -1 && $.inArray(d, keys) != -1) { // w + d
          console.log('function for w + d combo');
        } else if ($.inArray(s, keys) != -1 && $.inArray(a, keys) != -1) { // s + a
          console.log('function for s + a combo');
        }
      })
      

      小提琴演示

      https://jsfiddle.net/Hastig/us00zdo6/

      【讨论】:

        【解决方案6】:

        如果您使用的是 esma6,则可以使用集合执行以下操作。

        const KEYS = new Set();
        
        $(document).keydown(function (e) {
           KEYS.add(e.which);
           if(KEYS.has(12) && KEYS.has(31)){
              //do something
           }
        });
        $(document).keyup(function (e) {
           KEYS.delete(e.which);
        });
        

        如果您希望用户将它们按在一起,您可以这样做:

        const KEYS = new Set(); // for other purposes
        const RECENT_KEYS = new Set(); // the recently pressed keys
        const KEY_TIMELAPSE = 100 // the miliseconds of difference between keys
        
        $(document).keydown(function (e) {
           KEYS.add(e.which);
           RECENT_KEYS.add(e.which);
           setTimeout(()=>{
              RECENT_KEYS.delete(e.which);
           }, KEY_TIMELAPSE);
           if(RECENT_KEYS.has(37) && RECENT_KEYS.has(38)){
              // Do something
           }
        });
        $(document).keyup(function (e) {
           KEYS.delete(e.which);
           RECENT_KEYS.delete(e.which);
        });
        

        这是一个代码笔https://codepen.io/Programador-Anonimo/pen/NoEeKM?editors=0010

        【讨论】:

          【解决方案7】:

          由于我的要点已过期(没有人使用它 :()我决定用更多 2017 解决方案更新答案。请查看以下内容。

          您可以使用我的 jquery 插件来检测快捷方式。

          它基本上会缓存事件并获取当前按下的键。如果按下所有键,则触发功能。

          https://github.com/maciekpaprocki/bindShortcut(已过期!)

          您在自述文件中简要说明了如何使用它。希望这可以帮助。反馈多于赞赏。

          2017 年编辑:

          现在是 2017 年,我们不需要 jQuery 插件来解决这样的问题。简而言之,您将需要这样的东西:

          let pressed = {};
          
          document.addEventListener('keydown', (event) => {
             pressed[event.key] = true;
          });
          document.addEventListener('keyup', (event) => {
             delete pressed[event.key];
          });
          
          //and now write your code
          document.addEventListener('keydown', (event) => {
            if(pressed[firstKey]&&pressed[secondKey]){
              //dosomething
            }
          });
          

          较旧的浏览器可能有一些怪癖,但是从 IE9 开始,除了少数不支持正确事件委托的操作系统(超级旧的 ubuntu 等)外,一切都应该可以正常工作。没有办法在它们中解决这个问题,因为这不是浏览器问题。

          在连接到布尔键的新 Mac 中有一些怪癖,例如大写锁定。

          阅读更多:https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names_and_Char_values

          【讨论】:

          • 很高兴看到一些代码。这个断开的链接使答案过时了。
          • 不幸的是,我看到我的要点已被删除。无论哪种方式。 2017 年这样的 jQuery 插件只是一个笑话,所以我会尽快用解决方案更新答案。如果我不反对我,直到我这样做:)
          【解决方案8】:

          根据@David Tang 的解决方案,这里有一个快速而肮脏的自定义捕获 Shift+Ctrl+A 组合:

          var pressedKeys = {};
          
          function checkPressedKeys() {
              var shiftPressed=false, ctrlPressed=false, aPressed=false;
              for (var i in pressedKeys) {
                  if (!pressedKeys.hasOwnProperty(i)) continue;
                  if(i==16){
                      shiftPressed=true;
                  }
                  else if(i==17){
                      ctrlPressed=true;
                  }
                  else if(i==65){
                      aPressed=true;
                  }
              }
              if(shiftPressed && ctrlPressed && aPressed){
                  //do whatever you want here.
              }
          }
          
          
          $(document).ready(function(){
              $(document).keydown(function (e) {
                  pressedKeys[e.which] = true;
                  checkPressedKeys();
              });
          
              $(document).keyup(function (e) {
                  delete pressedKeys[e.which];
              });
          });
          

          【讨论】:

            猜你喜欢
            • 2013-09-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-02-16
            • 2020-02-14
            • 2012-09-25
            • 2013-10-21
            • 2016-01-27
            相关资源
            最近更新 更多