Answers:
如果您了解此概念,则可以轻松进行多次击键检测
我这样做的方式是这样的:
var map = {}; // You could also use an array
onkeydown = onkeyup = function(e){
e = e || event; // to deal with IE
map[e.keyCode] = e.type == 'keydown';
/* insert conditional here */
}
这段代码非常简单:由于计算机一次只传递一个按键,因此创建了一个数组来跟踪多个按键。然后可以使用该阵列一次检查一个或多个键。
只是为了说明一下,假设您按下A和B,每个按钮都会触发一个keydown
事件,该事件设置map[e.keyCode]
为的值e.type == keydown
,其结果为true或false。现在map[65]
和map[66]
都设置为true
。当您放开时A
,该keyup
事件将触发,并导致相同的逻辑来确定map[65]
(A)的相反结果,该结果现在为false,但是由于map[66]
(B)仍处于“按下”状态(尚未触发键入事件),它仍然是真的。
map
通过这两个事件的数组如下所示:
// keydown A
// keydown B
[
65:true,
66:true
]
// keyup A
// keydown B
[
65:false,
66:true
]
您现在可以做两件事:
A)可以创建Key logger(示例)作为参考,以便以后您想快速找出一个或多个键代码时使用。假设您已经定义了一个html元素,并使用变量指向了它element
。
element.innerHTML = '';
var i, l = map.length;
for(i = 0; i < l; i ++){
if(map[i]){
element.innerHTML += '<hr>' + i;
}
}
注意:您可以通过其id
属性轻松获取元素。
<div id="element"></div>
这将创建一个html元素,可以轻松地在javascript中使用 element
alert(element); // [Object HTMLDivElement]
您甚至不必使用document.getElementById()
或$()
抓住它。但是为了兼容性,请使用jQuery$()
更广泛地建议。
只要确保script标签在HTML正文之后即可。优化提示:大多数大牌网站把脚本标签后 body标签进行优化。这是因为script标记阻止其他元素加载,直到其脚本完成下载为止。将其放在内容之前可以预先加载内容。
B(您感兴趣的地方)您可以一次查看一个或多个键,/*insert conditional here*/
例如:
if(map[17] && map[16] && map[65]){ // CTRL+SHIFT+A
alert('Control Shift A');
}else if(map[17] && map[16] && map[66]){ // CTRL+SHIFT+B
alert('Control Shift B');
}else if(map[17] && map[16] && map[67]){ // CTRL+SHIFT+C
alert('Control Shift C');
}
编辑:这不是最可读的代码段。可读性很重要,因此您可以尝试这样的操作以使其更容易被使用:
function test_key(selkey){
var alias = {
"ctrl": 17,
"shift": 16,
"A": 65,
/* ... */
};
return key[selkey] || key[alias[selkey]];
}
function test_keys(){
var keylist = arguments;
for(var i = 0; i < keylist.length; i++)
if(!test_key(keylist[i]))
return false;
return true;
}
用法:
test_keys(13, 16, 65)
test_keys('ctrl', 'shift', 'A')
test_key(65)
test_key('A')
这是否更好?
if(test_keys('ctrl', 'shift')){
if(test_key('A')){
alert('Control Shift A');
} else if(test_key('B')){
alert('Control Shift B');
} else if(test_key('C')){
alert('Control Shift C');
}
}
(编辑结束)
本实施例中检查CtrlShiftA,CtrlShiftB和CtrlShiftC
就这么简单:)
通常,对代码进行文档记录是一种很好的做法,尤其是诸如键代码之类的东西(如 // CTRL+ENTER
),这样您就可以记住它们是什么。
您还应该将键控代码与文档(CTRL+ENTER => map[17] && map[13]
,NOT map[13] && map[17]
)放在相同的顺序。这样,当您需要返回并编辑代码时,您永远不会感到困惑。
如果检查不同数量的组合(如CtrlShiftAltEnter和CtrlEnter),则将较小的组合放在较大的组合之后,否则,如果较小的组合足够相似,则它们将覆盖较大的组合。例:
// Correct:
if(map[17] && map[16] && map[13]){ // CTRL+SHIFT+ENTER
alert('Whoa, mr. power user');
}else if(map[17] && map[13]){ // CTRL+ENTER
alert('You found me');
}else if(map[13]){ // ENTER
alert('You pressed Enter. You win the prize!')
}
// Incorrect:
if(map[17] && map[13]){ // CTRL+ENTER
alert('You found me');
}else if(map[17] && map[16] && map[13]){ // CTRL+SHIFT+ENTER
alert('Whoa, mr. power user');
}else if(map[13]){ // ENTER
alert('You pressed Enter. You win the prize!');
}
// What will go wrong: When trying to do CTRL+SHIFT+ENTER, it will
// detect CTRL+ENTER first, and override CTRL+SHIFT+ENTER.
// Removing the else's is not a proper solution, either
// as it will cause it to alert BOTH "Mr. Power user" AND "You Found Me"
在处理警报或任何需要主窗口关注的内容时,您可能需要map = []
在条件完成后包括重置阵列。这是因为某些事情(例如alert()
)会将焦点从主窗口移开,并导致“ keyup”事件不触发。例如:
if(map[17] && map[13]){ // CTRL+ENTER
alert('Oh noes, a bug!');
}
// When you Press any key after executing this, it will alert again, even though you
// are clearly NOT pressing CTRL+ENTER
// The fix would look like this:
if(map[17] && map[13]){ // CTRL+ENTER
alert('Take that, bug!');
map = {};
}
// The bug no longer happens since the array is cleared
我发现这是一件令人烦恼的事情,其中包括解决方案:
问题:由于浏览器通常在组合键上具有默认操作(例如,CtrlD激活书签窗口或CtrlShiftC在maxthon上激活skynote),因此您可能还需要添加return false
after map = []
,因此当“重复文件”出现时,您网站的用户不会感到沮丧功能,放在上CtrlD,将页面标记为书签。
if(map[17] && map[68]){ // CTRL+D
alert('The bookmark window didn\'t pop up!');
map = {};
return false;
}
没有return false
,“书签”窗口将弹出,使用户感到沮丧。
好的,因此您不一定总是要在此时退出该功能。这就是event.preventDefault()
功能所在的原因。它的作用是设置一个内部标志,告诉解释,以不使浏览器运行的默认操作。之后,继续执行功能(而return
将立即退出功能)。
在决定是否使用return false
或区分之前,请先了解这种区别。e.preventDefault()
event.keyCode
不推荐使用用户SeanVieira在event.keyCode
已弃用的评论中指出。
在那里,他给出了一个极好的选择:event.key
,它返回所按下键的字符串表示形式,例如"a"
for A或"Shift"
forShift。
我继续做饭,准备了一种检查所说弦的工具。
element.onevent
与 element.addEventListener
addEventListener
可向其注册的处理程序可以堆叠,并按注册顺序调用,而.onevent
直接设置则相当激进,并会覆盖您以前拥有的任何内容。
document.body.onkeydown = function(ev){
// do some stuff
ev.preventDefault(); // cancels default actions
return false; // cancels this function as well as default actions
}
document.body.addEventListener("keydown", function(ev){
// do some stuff
ev.preventDefault() // cancels default actions
return false; // cancels this function only
});
该.onevent
属性似乎覆盖了所有内容和行为,ev.preventDefault()
并且return false;
可能是不可预测的。
在这两种情况下,addEventlistener
似乎都更容易编写和推理通过处理程序注册的处理程序。
还有attachEvent("onevent", callback)
Internet Explorer的非标准实现,但这已被弃用,甚至与JavaScript不相关(它与称为JScript的深奥语言有关)。您的最大利益就是尽可能避免使用多语种代码。
为了解决混乱/投诉,我编写了一个进行此类抽象的“类”(pastebin link):
function Input(el){
var parent = el,
map = {},
intervals = {};
function ev_kdown(ev)
{
map[ev.key] = true;
ev.preventDefault();
return;
}
function ev_kup(ev)
{
map[ev.key] = false;
ev.preventDefault();
return;
}
function key_down(key)
{
return map[key];
}
function keys_down_array(array)
{
for(var i = 0; i < array.length; i++)
if(!key_down(array[i]))
return false;
return true;
}
function keys_down_arguments()
{
return keys_down_array(Array.from(arguments));
}
function clear()
{
map = {};
}
function watch_loop(keylist, callback)
{
return function(){
if(keys_down_array(keylist))
callback();
}
}
function watch(name, callback)
{
var keylist = Array.from(arguments).splice(2);
intervals[name] = setInterval(watch_loop(keylist, callback), 1000/24);
}
function unwatch(name)
{
clearInterval(intervals[name]);
delete intervals[name];
}
function detach()
{
parent.removeEventListener("keydown", ev_kdown);
parent.removeEventListener("keyup", ev_kup);
}
function attach()
{
parent.addEventListener("keydown", ev_kdown);
parent.addEventListener("keyup", ev_kup);
}
function Input()
{
attach();
return {
key_down: key_down,
keys_down: keys_down_arguments,
watch: watch,
unwatch: unwatch,
clear: clear,
detach: detach
};
}
return Input();
}
此类不会做所有事情,并且不会处理所有可能的用例。我不是图书馆员。但是对于一般的交互使用来说应该没问题。
要使用此类,请创建一个实例并将其指向您要将键盘输入与之关联的元素:
var input_txt = Input(document.getElementById("txt"));
input_txt.watch("print_5", function(){
txt.value += "FIVE ";
}, "Control", "5");
这样做是使用将一个新的输入侦听器附加到元素上#txt
(假设它是一个textarea),并为key组合设置一个观察点Ctrl+5
。当Ctrl
和5
都关闭时,将调用您传入的回调函数(在本例中为添加"FIVE "
到textarea 的函数)。回调与名称相关联print_5
,因此只需将其删除即可:
input_txt.unwatch("print_5");
要input_txt
与txt
元素分离:
input_txt.detach();
这样,垃圾收集可以捡起对象(input_txt
),如果将其丢弃,则不会留下旧的僵尸事件侦听器。
为了更全面,这里是C / Java样式的类API的快速参考,因此您知道它们返回的内容以及期望的参数。
Boolean key_down (String key);
true
如果key
关闭则返回,否则返回false。Boolean keys_down (String key1, String key2, ...);
true
如果所有键key1 .. keyN
都按下,则返回,否则返回false。void watch (String name, Function callback, String key1, String key2, ...);
创建一个“观察点”,以便按全部
keyN
将触发回调void unwatch (String name);
通过名称删除所述观察点
void clear (void);
擦除“按键按下”缓存。相当于
map = {}
以上void detach (void);
从父元素分离出
ev_kdown
和ev_kup
侦听器,从而可以安全地摆脱实例
更新2017-12-02为了响应将其发布到github的请求,我创建了一个gist。
更新2018-07-21我已经玩了一段时间的声明式样式编程,这种方式现在是我个人最喜欢的方式:小提琴手,pastebin
通常,它可以与您实际想要的情况(ctrl,alt,shift)一起使用,但是如果您需要同时打,例如,a+w
将这些方法“组合”为一个结构并不难。多键查找。
我希望这个详尽解释的答案迷你博客对您有所帮助:)
return false
vspreventDefault()
myString[5]
与相同5[myString]
,并且甚至不会给出编译警告(即使使用-Wall -pedantic
)?这是因为pointer[offset]
符号使用了指针,添加了偏移量,然后取消了对结果的引用,使其myString[5]
与相同*(myString + 5)
。
您应该使用keydown事件来跟踪按下的键,并且应该使用keyup事件来跟踪释放键的时间。
参见以下示例:http : //jsfiddle.net/vor0nwe/mkHsU/
(更新:我在这里重现代码,以防jsfiddle.net失败:) HTML:
<ul id="log">
<li>List of keys:</li>
</ul>
...和Javascript(使用jQuery):
var log = $('#log')[0],
pressedKeys = [];
$(document.body).keydown(function (evt) {
var li = pressedKeys[evt.keyCode];
if (!li) {
li = log.appendChild(document.createElement('li'));
pressedKeys[evt.keyCode] = li;
}
$(li).text('Down: ' + evt.keyCode);
$(li).removeClass('key-up');
});
$(document.body).keyup(function (evt) {
var li = pressedKeys[evt.keyCode];
if (!li) {
li = log.appendChild(document.createElement('li'));
}
$(li).text('Up: ' + evt.keyCode);
$(li).addClass('key-up');
});
在该示例中,我使用数组来跟踪按下了哪些键。在实际的应用程序中,您可能想要delete
释放每个元素的关联键。
请注意,尽管在此示例中我使用jQuery简化了工作,但该概念在“原始” Javascript中工作时同样有效。
onblur
事件处理程序,该事件处理程序将从数组中删除所有按下的键。一旦失去焦点,就必须再次按所有键。不幸的是,没有JS等效于GetKeyboardState
。
document.onkeydown = keydown;
function keydown (evt) {
if (!evt) evt = event;
if (evt.ctrlKey && evt.altKey && evt.keyCode === 115) {
alert("CTRL+ALT+F4");
} else if (evt.shiftKey && evt.keyCode === 9) {
alert("Shift+TAB");
}
}
我用这种方式(必须检查Shift + Ctrl是否按下):
// create some object to save all pressed keys
var keys = {
shift: false,
ctrl: false
};
$(document.body).keydown(function(event) {
// save status of the button 'pressed' == 'true'
if (event.keyCode == 16) {
keys["shift"] = true;
} else if (event.keyCode == 17) {
keys["ctrl"] = true;
}
if (keys["shift"] && keys["ctrl"]) {
$("#convert").trigger("click"); // or do anything else
}
});
$(document.body).keyup(function(event) {
// reset status of the button 'released' == 'false'
if (event.keyCode == 16) {
keys["shift"] = false;
} else if (event.keyCode == 17) {
keys["ctrl"] = false;
}
});
对于谁需要完整的示例代码。向右向左添加
var keyPressed = {};
document.addEventListener('keydown', function(e) {
keyPressed[e.key + e.location] = true;
if(keyPressed.Shift1 == true && keyPressed.Control1 == true){
// Left shift+CONTROL pressed!
keyPressed = {}; // reset key map
}
if(keyPressed.Shift2 == true && keyPressed.Control2 == true){
// Right shift+CONTROL pressed!
keyPressed = {};
}
}, false);
document.addEventListener('keyup', function(e) {
keyPressed[e.key + e.location] = false;
keyPressed = {};
}, false);
我会尝试在添加keypress
Event
处理程序keydown
。例如:
window.onkeydown = function() {
// evaluate key and call respective handler
window.onkeypress = function() {
// evaluate key and call respective handler
}
}
window.onkeyup = function() {
window.onkeypress = void(0) ;
}
这只是为了说明一种模式。我在这里不做详细介绍(尤其是不针对特定于浏览器的level2 + Event
注册)。
请发回是否有帮助。
如果按下的键之一是Alt / Crtl / Shift,则可以使用以下方法:
document.body.addEventListener('keydown', keysDown(actions) );
function actions() {
// do stuff here
}
// simultaneous pressing Alt + R
function keysDown (cb) {
return function (zEvent) {
if (zEvent.altKey && zEvent.code === "KeyR" ) {
return cb()
}
}
}
$(document).ready(function () {
// using ascii 17 for ctrl, 18 for alt and 83 for "S"
// ctr+alt+S
var map = { 17: false, 18: false, 83: false };
$(document).keyup(function (e) {
if (e.keyCode in map) {
map[e.keyCode] = true;
if (map[17] && map[18] && map[83]) {
// Write your own code here, what you want to do
map[17] = false;
map[18] = false;
map[83] = false;
}
}
else {
// if u press any other key apart from that "map" will reset.
map[17] = false;
map[18] = false;
map[83] = false;
}
});
});
这不是通用方法,但在某些情况下很有用。对于CTRL+ something或Shift+ something或CTRL+ Shift+ 等组合非常有用something等。
示例:当您想使用CTRL+ 打印页面时P,总是CTRL先按下第一个键P。与CTRL+ S,CTRL+ U和其他组合相同。
document.addEventListener('keydown',function(e){
//SHIFT + something
if(e.shiftKey){
switch(e.code){
case 'KeyS':
console.log('Shift + S');
break;
}
}
//CTRL + SHIFT + something
if(e.ctrlKey && e.shiftKey){
switch(e.code){
case 'KeyS':
console.log('CTRL + Shift + S');
break;
}
}
});
Easiest, and most Effective Method
//check key press
function loop(){
//>>key<< can be any string representing a letter eg: "a", "b", "ctrl",
if(map[*key*]==true){
//do something
}
//multiple keys
if(map["x"]==true&&map["ctrl"]==true){
console.log("x, and ctrl are being held down together")
}
}
//>>>variable which will hold all key information<<
var map={}
//Key Event Listeners
window.addEventListener("keydown", btnd, true);
window.addEventListener("keyup", btnu, true);
//Handle button down
function btnd(e) {
map[e.key] = true;
}
//Handle Button up
function btnu(e) {
map[e.key] = false;
}
//>>>If you want to see the state of every Key on the Keybaord<<<
setInterval(() => {
for (var x in map) {
log += "|" + x + "=" + map[x];
}
console.log(log);
log = "";
}, 300);