如何检测何时释放所有键
How to detect when all keys are released
下面的代码应该测量一个键(或多个键)被按下的时间。
var output = document.getElementById('output'),
pressed = {};
window.onkeydown = function(e) {
if ( pressed[e] ) return;
pressed[e] = e.timeStamp;
};
window.onkeyup = function(e) {
if ( !pressed[e] ) return;
var duration = ( e.timeStamp - pressed[e] ) / 1000;
var today = new Date();
var date = today.getDate()+'-'+(today.getMonth()+1)+'-'+today.getFullYear();
var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
var dateTime = date+' '+time;
output.innerHTML += dateTime + ' - Key(s) pressed for ' + duration + ' seconds</p>';
pressed[e] = 0;
}
<div id="output"></div>
有什么办法可以改变window.onkeyup函数,让它只在释放所有键时输出日志吗?
示例:
10:00:00 - 我按住 A
10:00:05 - 我按住 B
10:00:20 - 我按住 C
10:00:22 - 我放A
10:00:24 - 我释放 B
10:00:30 - 我释放 C
当前代码输出:
26-2-2021 10:00:22 - 按键持续 22 秒
26-2-2021 10:00:24 - 按键持续 2 秒
26-2-2021 10:00:30 - 按键持续 6 秒
预期输出:
26-2-2021 10:00:30 - 按键持续 30 秒
感谢您的帮助。
您可以用另一个值改进您的 pressed
地图,即 is_down
并在最后检查它。
window.onkeydown = function(e) {
if ( pressed[e.key] ) return;
pressed[e.key] = {time:e.timeStamp, is_down:true}
};
然后在发布时检查是否有人 is_down:true
。
window.onkeyup = function(e) {
if ( !pressed?.is_down ) return;
var duration = ( e.timeStamp - pressed[e.key].time ) / 1000;
var is_all_released = Object.keys(pressed).filter(key => pressed[key].is_down).length > 0
if (is_all_released) {
//do your printouts
}
首先,你应该做 pressed[e.code]
,而不是 pressed[e]
,因为这个 e
对象值将被字符串化为 [object KeyboardEvent]
,所以你只分配给一个和相同的属性,在每个键盘事件上。
要仅在所有键都弹起时报告,请跟踪计数和按下第一个键的时间:
var output = document.getElementById('output'),
pressed = {},
keyDownCount = 0,
keyDownTime = 0;
window.onkeydown = function(e) {
if ( pressed[e.code] ) return;
pressed[e.code] = true;
if (!keyDownCount) keyDownTime = e.timeStamp;
keyDownCount++;
};
window.onkeyup = function(e) {
if ( !pressed[e.code] ) return;
pressed[e.code] = false;
keyDownCount--;
if (keyDownCount) return;
var duration = ( e.timeStamp - keyDownTime ) / 1000;
var today = new Date();
var date = today.getDate()+'-'+(today.getMonth()+1)+'-'+today.getFullYear();
var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
var dateTime = (date+' '+time).replace(/\b\d\b/g, "0$&");
output.innerHTML += dateTime + ' - Key(s) pressed for ' + duration + ' seconds</p>';
}
<div id="output"></div>
请注意,这并非完全防弹。如果有人关注另一个 window 并更改返回前按下的键,这些更改将不会触发事件。
要使它正常工作,您需要进行一些更改。
首先,当您在释放所有键后重置缓存的时间戳时,您应该删除条目而不是仅仅将时间戳设置为 0 - 这样您将在下次按下多个键时再次从一个空对象开始。
您可以为此使用 delete
关键字。
此外,据我了解,您实际上只想比较第一个时间戳和最后一个时间戳,以获得您按下按键的总时间。所以我建议你的解决方案是(我也重构了一点):
const output = document.getElementById('output');
let pressed = {};
window.onkeydown = function (e) {
if (Object.values(pressed).length <= 1) {
pressed.start = new Date();
}
pressed[e.code] = e.timeStamp;
};
window.onkeyup = function (e) {
delete pressed[e.code];
const { start, ...rest } = pressed;
if (rest.length <= 1) {
const currentTime = new Date();
const duration = (currentTime - start) / 1000;
const date = `${currentTime.getDate()}-${currentTime.getMonth() + 1}-${currentTime.getFullYear()}`;
const time = `${currentTime.getHours()}:${currentTime.getMinutes() + 1}:${currentTime.getSeconds()}`;
output.innerHTML += `${date} ${time} - Key(s) pressed for ${duration} seconds</p>`;
delete pressed.start;
}
};
您可以使用 Set
然后在从集合中删除最后一个键时执行一些代码(如下面的 onRelease
方法)。要知道持续时间是多少,您还必须跟踪按下第一个键的时间。
下面的示例将逻辑和回调函数移动到 pressed
对象中,但您可以通过多种方式进行设置。
const output = document.getElementById("output");
function log(text) {
const p = document.createElement("p");
p.append(text);
output.append(p);
}
const pressed = {
keys: new Set(),
timestamp: null,
get isEmpty() { return !this.keys.size },
add(key) {
// save the current timestamp when adding the first key
if (this.isEmpty) this.timestamp = Date.now();
return this.keys.add(key);
},
delete(key) {
const wasPresent = this.keys.delete(key);
// trigger onRelease when deleting the last key
if (wasPresent && this.isEmpty) this.onRelease();
return wasPresent;
},
onRelease() {
const now = new Date();
const duration = now.getTime() - this.timestamp;
log(`${now.toLocaleString()} - Key(s) pressed for ${duration}ms`);
}
};
document.addEventListener("keydown", ({ code }) => pressed.add(code));
document.addEventListener("keyup", ({ code }) => pressed.delete(code));
<div id="output"></div>
与其他答案类似,“keydown”和“keyup”只有在当前选项卡中的页面处于活动状态时才会触发。当键是 pressed/released 而在另一个 tab/window 上时,它们将不会注册到 JavaScript。
下面的代码应该测量一个键(或多个键)被按下的时间。
var output = document.getElementById('output'),
pressed = {};
window.onkeydown = function(e) {
if ( pressed[e] ) return;
pressed[e] = e.timeStamp;
};
window.onkeyup = function(e) {
if ( !pressed[e] ) return;
var duration = ( e.timeStamp - pressed[e] ) / 1000;
var today = new Date();
var date = today.getDate()+'-'+(today.getMonth()+1)+'-'+today.getFullYear();
var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
var dateTime = date+' '+time;
output.innerHTML += dateTime + ' - Key(s) pressed for ' + duration + ' seconds</p>';
pressed[e] = 0;
}
<div id="output"></div>
有什么办法可以改变window.onkeyup函数,让它只在释放所有键时输出日志吗?
示例:
10:00:00 - 我按住 A
10:00:05 - 我按住 B
10:00:20 - 我按住 C
10:00:22 - 我放A
10:00:24 - 我释放 B
10:00:30 - 我释放 C
当前代码输出:
26-2-2021 10:00:22 - 按键持续 22 秒
26-2-2021 10:00:24 - 按键持续 2 秒
26-2-2021 10:00:30 - 按键持续 6 秒
预期输出:
26-2-2021 10:00:30 - 按键持续 30 秒
感谢您的帮助。
您可以用另一个值改进您的 pressed
地图,即 is_down
并在最后检查它。
window.onkeydown = function(e) {
if ( pressed[e.key] ) return;
pressed[e.key] = {time:e.timeStamp, is_down:true}
};
然后在发布时检查是否有人 is_down:true
。
window.onkeyup = function(e) {
if ( !pressed?.is_down ) return;
var duration = ( e.timeStamp - pressed[e.key].time ) / 1000;
var is_all_released = Object.keys(pressed).filter(key => pressed[key].is_down).length > 0
if (is_all_released) {
//do your printouts
}
首先,你应该做 pressed[e.code]
,而不是 pressed[e]
,因为这个 e
对象值将被字符串化为 [object KeyboardEvent]
,所以你只分配给一个和相同的属性,在每个键盘事件上。
要仅在所有键都弹起时报告,请跟踪计数和按下第一个键的时间:
var output = document.getElementById('output'),
pressed = {},
keyDownCount = 0,
keyDownTime = 0;
window.onkeydown = function(e) {
if ( pressed[e.code] ) return;
pressed[e.code] = true;
if (!keyDownCount) keyDownTime = e.timeStamp;
keyDownCount++;
};
window.onkeyup = function(e) {
if ( !pressed[e.code] ) return;
pressed[e.code] = false;
keyDownCount--;
if (keyDownCount) return;
var duration = ( e.timeStamp - keyDownTime ) / 1000;
var today = new Date();
var date = today.getDate()+'-'+(today.getMonth()+1)+'-'+today.getFullYear();
var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
var dateTime = (date+' '+time).replace(/\b\d\b/g, "0$&");
output.innerHTML += dateTime + ' - Key(s) pressed for ' + duration + ' seconds</p>';
}
<div id="output"></div>
请注意,这并非完全防弹。如果有人关注另一个 window 并更改返回前按下的键,这些更改将不会触发事件。
要使它正常工作,您需要进行一些更改。 首先,当您在释放所有键后重置缓存的时间戳时,您应该删除条目而不是仅仅将时间戳设置为 0 - 这样您将在下次按下多个键时再次从一个空对象开始。
您可以为此使用 delete
关键字。
此外,据我了解,您实际上只想比较第一个时间戳和最后一个时间戳,以获得您按下按键的总时间。所以我建议你的解决方案是(我也重构了一点):
const output = document.getElementById('output');
let pressed = {};
window.onkeydown = function (e) {
if (Object.values(pressed).length <= 1) {
pressed.start = new Date();
}
pressed[e.code] = e.timeStamp;
};
window.onkeyup = function (e) {
delete pressed[e.code];
const { start, ...rest } = pressed;
if (rest.length <= 1) {
const currentTime = new Date();
const duration = (currentTime - start) / 1000;
const date = `${currentTime.getDate()}-${currentTime.getMonth() + 1}-${currentTime.getFullYear()}`;
const time = `${currentTime.getHours()}:${currentTime.getMinutes() + 1}:${currentTime.getSeconds()}`;
output.innerHTML += `${date} ${time} - Key(s) pressed for ${duration} seconds</p>`;
delete pressed.start;
}
};
您可以使用 Set
然后在从集合中删除最后一个键时执行一些代码(如下面的 onRelease
方法)。要知道持续时间是多少,您还必须跟踪按下第一个键的时间。
下面的示例将逻辑和回调函数移动到 pressed
对象中,但您可以通过多种方式进行设置。
const output = document.getElementById("output");
function log(text) {
const p = document.createElement("p");
p.append(text);
output.append(p);
}
const pressed = {
keys: new Set(),
timestamp: null,
get isEmpty() { return !this.keys.size },
add(key) {
// save the current timestamp when adding the first key
if (this.isEmpty) this.timestamp = Date.now();
return this.keys.add(key);
},
delete(key) {
const wasPresent = this.keys.delete(key);
// trigger onRelease when deleting the last key
if (wasPresent && this.isEmpty) this.onRelease();
return wasPresent;
},
onRelease() {
const now = new Date();
const duration = now.getTime() - this.timestamp;
log(`${now.toLocaleString()} - Key(s) pressed for ${duration}ms`);
}
};
document.addEventListener("keydown", ({ code }) => pressed.add(code));
document.addEventListener("keyup", ({ code }) => pressed.delete(code));
<div id="output"></div>
与其他答案类似,“keydown”和“keyup”只有在当前选项卡中的页面处于活动状态时才会触发。当键是 pressed/released 而在另一个 tab/window 上时,它们将不会注册到 JavaScript。