在“点击”事件中检查Ctrl / Shift / Alt键

89

如何在以下代码中确定按下了哪个 Ctrl / Shift / Alt 键?

$("#my_id").click(function() {
    if (<left control key is pressed>) { alert("Left Ctrl"); }
    if (<right shift and left alt keys are pressed>) { alert("Right Shift + Left Alt"); }
});

@JeremyBanks 你正在寻找KeyboardEvent Location请参见表格支持。在jQuery中,使用jq事件包装器,您需要使用event.originalEvent.location。然后,在单击上实现逻辑并不那么困难,只需在keydown / keyup事件上设置一些标志/对象,并在单击时进行检查。问题可能是处理altGr键,它可能会给出不一致的结果。如果我有时间,我会稍后回答。 - A. Wolff
10个回答

86

在所有浏览器中这种方法不起作用,只有IE 8支持。微软实现了确定键盘左右方向键的能力。这里是一个链接:http://msdn.microsoft.com/en-us/library/ms534630(VS.85).aspx

我还发现了一篇关于浏览器中按键事件keypress、keyup、keydown的精彩文章。http://unixpapa.com/js/key.html

$('#someelement').bind('click', function(event){ 

    if(event.ctrlKey) {
      if (event.ctrlLeft) {
        console.log('ctrl-left'); 
      }
      else {
        console.log('ctrl-right');
      }
    }
    if(event.altKey) {
      if (event.altLeft) {
        console.log('alt-left'); 
      }
      else {
        console.log('alt-right');
      }
    }
    if(event.shiftKey) {
      if (event.shiftLeft) {
        console.log('shift-left'); 
      }
      else
      {
        console.log('shift-right');
      }
    }
  }); 

抱歉,我没有提到我对Firefox 3.6.3感兴趣。我已经相应地更新了问题。 - Misha Moroshko
Misha Moroshko。很抱歉,目前在Firefox中还没有办法做到这一点。也许将来会实现“keyLocation”、“keyIdentifier”或“shiftLeft”。我有一个疯狂的建议,但不确定是否可行。我知道JAVA applets有检测右键和左键击键的能力。如果您可以在applet中捕获击键,并将右/左信息传回网站。我甚至无法告诉您如何做到这一点,但这是一个想法。Flash可能是JAVA applet的替代方案。 - John Hartsock
是的,我想你不会这样做。但现在使用JQuery/HTML DOM和Firefox 3.6.3还不可能实现。 - John Hartsock
同样地,您也可以使用一些Flash Actionscript3来完成它,但我猜您也不想去那里。 - mVChr
另一条评论中的quirksmode链接表明这是IE6+而不仅仅是IE8... - Stobor
好的,Stobor说得不错,但由于他正在寻找Firefox 3.6.3的解决方案,所以那有点不相关。 - John Hartsock

40
$('#someelement').bind('click', function(event){
   if(event.ctrlKey)
      console.log('ctrl');
   if(event.altKey)
      console.log('alt');
   if(event.shiftKey)
      console.log('shift');

});

我不知道在点击事件中是否可能检查左/右键,但我认为这是不可能的。


1
向左和向右移位键的键值都为16。Ctrl键(17)和alt键(18)也是如此。 - Tom
9
我认为你需要等待DOM3支持,才能区分左右。DOM 3引入了event.keyLocation属性(http://www.w3.org/TR/DOM-Level-3-Events/#events-Events-KeyboardEvent-keylocation)。 - DaveS
Firefox 3.6.3 是否有这个实现的可能性? - Misha Moroshko
2
似乎Firefox尚未实现左/右功能。对于Shift,您可以标记一个功能请求:https://bugzilla.mozilla.org/show_bug.cgi?id=458433 ctrlLeft甚至没有错误/功能请求。Quirksmode页面(虽然缺少有关任何最近浏览器的信息):http://www.quirksmode.org/dom/w3c_events.html#keyprops - Simon B.

10
e.originalEvent.location 返回 1 表示按下左键,返回 2 表示按下右键。因此,您可以像以下示例一样检测哪个 修饰键 被按下。希望这能帮助您。

var msg = $('#msg');
$(document).keyup(function (e) {
      if (e.keyCode == 16) {
          if (e.originalEvent.location == 1)
              msg.html('Left SHIFT pressed.');
          else
              msg.html('Right SHIFT pressed.');
      } else if (e.keyCode == 17) {
          if (e.originalEvent.location == 1)
              msg.html('Left CTRL pressed.');
          else
              msg.html('Right CTRL pressed.');
      } else if (e.keyCode == 18) {
          if (e.originalEvent.location == 1)
              msg.html('Left ALT pressed.');
          else
              msg.html('Right ALT pressed.');
        
          e.preventDefault(); //because ALT focusout the element
      }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label>Press modifier key: </label>
<strong id="msg"></strong>


我在Chrome中快速查看了一下,得到了与您相同的结果。请使用event.locationevent.keyLocation,并可能回退到event.ctrlLeft语法以支持IE OLDTIMER。 - Tokimon
在Chrome中,使用event.location是我唯一有效的方法,用于区分左侧键和右侧键。 - Mac
e.originalEvent.location 在 Chrome 和 Firefox 中都能正常工作。@Mac - Ibrahim Khan
似乎使用 keyup 有点奇怪...如果你想知道在 click 中是否按下了 Ctrl 键,你应该使用 keydown 并设置一个标志,然后在点击监听器中检查它。在 keyup 中重置该标志。 - Stijn de Witt

8

在大多数情况下,ALTCTRLSHIFT 键的布尔值可以用来检测这些键是否被按下。例如:

var altKeyPressed = instanceOfMouseEvent.altKey

当被调用时,它将返回true或false。更多信息请访问https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/altKey 未来参考,还有一个名为metaKey(仅限NS / firefox)在按下meta键时起作用。

这可能是这里最好的答案。有趣的是它没有赞同票。 - MarkSkayff
值得注意的是,如果用户使用默认设置的Linux Mint 18,则此简单解决方案可能会失败。如果在首选项:Windows:行为:特殊键移动和调整窗口中找到的操作系统设置设置为Alt(默认情况下是这样),则按住Alt将导致“click”事件不被触发,因此引用“altKey”属性的函数将永远不会被执行。 - Patrick Dark

7

我认为我应该加入一个适用于2020年的答案。


现在,您还可以使用MouseEvent.getModifierState()来实现此功能 - 根据撰写时的时间,它已得到大多数浏览器的支持

document.addEventListener("click", (evn) => {
  const shift = evn.getModifierState("Shift");
  const ctrl = evn.getModifierState("Control");
  const alt = evn.getModifierState("Alt");

  console.log("Mouse pressed! Modifiers:");
  console.table({shift, ctrl, alt});
});

Example

注意事项:

  • 需要注意的是,此API不能区分左右修饰键。如果您关心这一点,那么可能就比较不幸了。但我想这只对少数用例有影响。
  • 此API的主要好处之一是支持shiftctrlalt以外的其他修饰键。然而,由于固有平台差异,其具体行为在不同操作系统上表现得相当不稳定。在使用它们之前,请查看这里

非常感谢。这样干净多了! - Austin Burk

2

以下是可能的解决方案,跟进我的评论

要检查按下哪个特定的修饰键,您可以使用KeyboardEvent Location请参阅表格支持)。

为了支持IE8,幸运的是,您可以使用已发布的解决方案

现在的解决方法是设置一个全局对象,其中包含有关所持有的修饰键的相关属性。当然还有其他不使用全局对象的方式。

在这里,我使用相关的javascript监听器方法来捕获事件 (jQuery不支持捕获阶段)。我们捕获事件以处理keydown/keyup事件传播由于已经在使用的代码而被停止的情况。

/* global variable used to check modifier keys held */
/* Note: if e.g control left key and control right key are held simultaneously */
/* only first pressed key is handled (default browser behaviour?)*/
window.modifierKeys = (function() {
  /* to handle modifier keys except AltGr which is key shortcut for controlRight + alt */
  var mKeys = {};
  /* to fire keydown event only once per key held*/
  var lastEvent, heldKeys = {};
  // capture event to avoid any event stopped propagation
  document.addEventListener('keydown', function(e) {
    if (lastEvent && lastEvent.which == e.which) {
      return;
    }
    lastEvent = e;
    heldKeys[e.which] = true;
    setModifierKey(e);
  }, true);
  // capture event to avoid any event stopped propagation
  document.addEventListener('keyup', function(e) {
    lastEvent = null;
    delete heldKeys[e.which];
    setModifierKey(e);
  }, true);

  function setModifierKey(e) {
    mKeys.alt = e.altKey;
    mKeys.ctrlLeft = e.ctrlKey && e.location === 1;
    mKeys.ctrlRight = e.ctrlKey && e.location === 2;
    mKeys.shiftLeft = e.shiftKey && e.location === 1;
    mKeys.shiftRight = e.shiftKey && e.location === 2;
  }
  return mKeys;
})();

/* on div click, check for global object */
$('.modifierKey').on('click', function() {
  console.log(modifierKeys);
  /* for demo purpose */
  $('.info').text(function() {
    var txt = [];
    for (var p in modifierKeys) {
      if (modifierKeys[p]) txt.push(p);
    }
    return txt.toString();
  });
})
/* for demo purpose */

.info:not(:empty) {
  border: 1px solid red;
  padding: .1em .5em;
  font-weight: bold;
}
.info:not(:empty):after {
  content: " held";
  font-weight: normal;
 }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="modifierKey" tabindex="-1">
  DIV to catch modifier keys on click
</div>
<br>
<span class="info"></span>

作为附注:

  • ALT GR键是CTRL-RightALT键的快捷键。
  • 同时按住两个相同的修饰键(如Shift-Left和Shift-Rigth键)只会处理第一个键(似乎是默认浏览器行为,所以无论如何都是正确的!)。

1

0

非常好用!而且在Chrome、Firefox、IE和Edge上都可以使用 ;) https://jsfiddle.net/55g5utsk/2/

var a=[];
function keyName(p){
    var cases = {16:'Shift',17:'CTRL',18:'Alt'};
    return cases[p] ? cases[p] : 'KeyCode: '+p;
}
function keyPosition(p){
    var cases = {1:'Left',2:'Right'};
    return cases[p] ? cases[p]+' ' : '';
}
$('input').on('keydown',function(e){
    a.push(keyPosition(e.originalEvent.location)+keyName(e.keyCode));
})
$('input').on('keyup',function(){
    var c='';
    var removeDuplicates = [];
    $.each(a, function(i, el){
        if ($.inArray(el, removeDuplicates) === -1) {
           removeDuplicates.push(el);
           c=c+(el)+' + ';
        }
    });
    a=[];
    alert(c.slice(0, -3))
});

以下是带有点击事件的版本: http://jsfiddle.net/2pL0tzx9/
var a=[];
function keyName(p){
    var cases = {16:'Shift',17:'CTRL',18:'Alt'};
    return cases[p] ? cases[p] : '';
}
function keyPosition(p){
    var cases = {1:'Left',2:'Right'};
    return cases[p] ? cases[p]+' ' : '';
}
$(document).on('keydown',function(e){
    a.push(keyPosition(e.originalEvent.location)+keyName(e.keyCode));
})
$('#my_id').on('click',function(){
    var c='';
    var removeDuplicates = [];
    a =a.filter(function(v){return v!==''});
    $.each(a, function(i, el){
      if ($.inArray(el, removeDuplicates) === -1){
          removeDuplicates.push(el);
          c=c+(el)+' + ';
      }
    });
    if (c) alert(c.slice(0, -3));
    a=[];   
});

0

有一些原因导致右侧和左侧的CTRLSHIFTALT键不可区分,因为: 1. 键码相同 2. 许多笔记本电脑键盘可能没有两个控制键。 参考资料: 如何判断事件是否来自右Ctrl键?


0
比任何事情都容易:使用 keydown 事件来检查它是否是 Ctrl(17)或 Shift(16),然后使用 keyup 事件来检查它是否是 Enter(13)并且在键按下时命中了 CtrlShift。 除了 Enter 键以外,任何 keyup 都要取消 CtrlShift

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接