目标是手动设置保持键的“重复率”。
例如,当在文本框中按住X键时,我明白有 浏览器特定的重复按下字符的方法。在某些情况下,它会暂停,然后不断触发按下的键。在其他情况下,它根本不重复。我想通过强制按下的键以特定间隔重复来缓解这种情况,无论浏览器如何。
通过研究,我想出了一个基于计时器的尝试,但在Safari中,它不会重复这个角色。我有一个菜单系统,按住箭头滚动列表,但翻译动画和重复率不相互喜欢。
var repeating = false;
var repeatRateTimer = null;
$( document ).bind( 'keyup', function( input ) {
if( repeatRateTimer != null )
{
clearTimeout( repeatRateTimer );
repeatRateTimer = null;
}
repeating = false;
} );
$( document ).bind( 'keydown', function( input ) {
input.preventDefault( );
if( repeating == true )
{
if( repeatRateTimer != null )
{
clearTimeout( repeatRateTimer );
repeatRateTimer = null;
}
else
{
repeatRateTimer = setTimeout( function( ){ repeating = false; }, 1000 );
}
return;
}
repeating = true;
// ...keyboard logic
} );
我可能把整个事情搞砸了......我试图重新创建一个简化版本 这个SO帖子。但是,我觉得那里 具有 做一个更好的方法。有什么想法吗?
更新:
我们可以假设最终用户没有将其OS键盘重复率设置为大于我想要使用的速率(1000ms)。如果是,那么它应该回落到它们的重复率,因为它不会继续触发按键事件。如果不是(更可能是因为大多数人不修改它),那么我们将覆盖该行为以使其延迟我们指定的时间段。
好吧,我弄清楚为什么我的例子没有循环。在keydown循环中,它在超时之前清除了超时:
if( repeatRateTimer != null )
{
clearTimeout( repeatRateTimer );
repeatRateTimer = null;
}
else
{
repeatRateTimer = setTimeout( function( ){ repeating = false; }, 1000 );
}
超时应该在它到期后才被清除,所以 if
条件需要移入超时功能:
if( repeatRateTimer == null )
{
repeatRateTimer = setTimeout( function( ) {
repeating = false;
clearTimeout( repeatRateTimer );
repeatRateTimer = null;
}, 1000 );
}
如果有人可以改进这一点,或者提供更好的选择,我将保留这笔赏金。
请看以下内容 JavaScript文件。如果向下滚动到第530行,您将找到以下类:
var Keyboard = new Class(function (constructor) {
var key = {};
var eventListener = {
keyup: {},
keydown: {},
keypress: {}
};
constructor.overload(["Number"], function (interval) {
setInterval(keypress, interval);
});
window.addEventListener("keyup", keyup, false);
window.addEventListener("keydown", keydown, false);
function keyup(event) {
var keyCode = event.keyCode;
var listener = eventListener.keyup[keyCode];
key[keyCode] = false;
if (listener)
listener();
}
function keydown(event) {
var keyCode = event.keyCode;
var listener = eventListener.keydown[keyCode];
key[keyCode] = true;
if (listener)
listener();
}
function keypress() {
for (var code in key) {
var listener = eventListener.keypress[code];
if (key[code] && listener) listener();
}
}
this.addEventListener = new Dispatcher(["String", "Number", "Function"], function (type, keyCode, listener) {
type = eventListener[type];
if (type) type[keyCode] = listener;
else throw new Error("Unexpected value for type.");
});
});
作者所做的是他创造了一个特别的 Keyboard
用于委派关键事件的类: keyup
, keydown
和 keypress
。该类只有一个构造函数接受一个参数 - 的间隔 keypress
事件(这是你想要的)。您可以使用以下命令添加事件侦听器 addEventListener
实例的方法 Keyboard
类:
var keyboard = new Keyboard(125); // fire key press 8 times a second.
keypress.addEventListener("keypress", 65, function () {
// do something every time A is pressed
});
请注意,上面的类取决于以下框架: Lambda JS。您可以看到上述脚本的工作演示 这里。希望这可以帮助。
更新1:
你的 码 在Opera中不起作用。此外,第二个事件在Firefox中额外延迟500毫秒后触发,并且连续事件不会保持相同的间隔。此外,它无法同时处理多个关键事件。让我们纠正这个问题:
首先,我们需要为其创建一个简单的脚本 Delta Timing 这样,关键事件会在恒定间隔后触发。我们使用以下代码段来创建 DeltaTimer
:
function DeltaTimer(render, interval) {
var timeout;
var lastTime;
this.start = start;
this.stop = stop;
function start() {
timeout = setTimeout(loop, 0);
lastTime = Date.now();
return lastTime;
}
function stop() {
clearTimeout(timeout);
return lastTime;
}
function loop() {
var thisTime = Date.now();
var deltaTime = thisTime - lastTime;
var delay = Math.max(interval - deltaTime, 0);
timeout = setTimeout(loop, delay);
lastTime = thisTime + delay;
render(thisTime);
}
}
接下来我们编写逻辑来解雇自定义 keypressed
事件。我们需要自定义事件,因为我们必须能够同时处理多个键:
(function (interval) {
var keyboard = {};
window.addEventListener("keyup", keyup, false);
window.addEventListener("keydown", keydown, false);
function keyup(event) {
keyboard[event.keyCode].pressed = false;
}
function keydown(event) {
var keyCode = event.keyCode;
var key = keyboard[keyCode];
if (key) {
if (!key.start)
key.start = key.timer.start();
key.pressed = true;
} else {
var timer = new DeltaTimer(function (time) {
if (key.pressed) {
var event = document.createEvent("Event");
event.initEvent("keypressed", true, true);
event.time = time - key.start;
event.keyCode = keyCode;
window.dispatchEvent(event);
} else {
key.start = 0;
timer.stop();
}
}, interval);
key = keyboard[keyCode] = {
pressed: true,
timer: timer
};
key.start = timer.start();
}
}
})(1000);
该 interval
被设定为 1000
ms但你可以改变它。最后注册我们做的事件:
window.addEventListener("keypressed", function (event) {
document.body.innerHTML += event.keyCode + " (" + event.time + " ms)<br/>";
}, false);
这是简单而有效的JavaScript。不需要jQuery。你可以看到 现场演示 在这里,看看你和我的脚本之间的区别。干杯。
更新2:
看着对方 题 在StackOverflow上,这是使用上述模式实现它的方法:
window.addEventListener("keypressed", function (event) {
switch (event.keyCode) {
case 37:
Move(-1, 0);
break;
case 38:
Move(0, -1);
break;
case 39:
Move(1, 0);
break;
case 40:
Move(0, 1);
break;
}
}, false);
使用上面的代码将消除您遇到的短暂延迟,并允许同时为不同的键触发多个事件。
你怎么做自定义键事件。你可以听原始的(keyup / keydown),如果他们通过时间条件,你就会触发自定义事件。
这种方式的好处是您不依赖于计时器,它可以为您提供更多功能,因为您使用自定义事件(顺便说一下,如果您愿意,可以跳过取消事件部分)。
这是一个演示,看看我在说什么: http://jsfiddle.net/gion_13/gxEMz/
基本代码看起来像这样:
$(document).ready(function(){
var dispatcher = $(window),
keyRate = 1000, //ms
lastKeyEvent = 0,
cancelEvent = function(e){
var evt = e ? e:window.event;
if(evt.stopPropagation)
evt.stopPropagation();
if(evt.cancelBubble!=null)
evt.cancelBubble = true;
return false;
};
dispatcher
.bind('keydown',function(e){
var now = new Date().getTime();
if(now - lastKeyEvent <= keyRate)
// cancel the event
return cancelEvent(e);
var keyEventsTimeDiff = now - lastKeyEvent;
lastKeyEvent = now;
dispatcher.trigger('special-keydown',[e,keyEventsTimeDiff ]);
})
.bind('keyup',function(e){
cancelEvent(e);
dispatcher.trigger('special-keyup',[e]);
})
// binding the custom events
.bind('special-keydown',function(e,keyEventsTimeDiff){
console.log(e,'special keydown triggered again after ' + keyEventsTimeDiff +'ms');
})
.bind('special-keyup',function(e,keyEventsTimeDiff){
console.log(e,'special keyup');
});
});