在JavaScript中,是否可以覆盖keydown重复延迟?

在JavaScript中,是否可以覆盖keydown重复延迟?,javascript,jquery,keypress,keydown,repeat,Javascript,Jquery,Keypress,Keydown,Repeat,目标是手动设置保持键的“重复率” 例如,当在文本框中按住X键时,我知道有。在某些情况下,它会暂停,然后连续触发按下的键。在其他情况下,它根本不会重复。我想通过强制按键以特定的间隔重复来缓解这种情况,而不考虑浏览器 通过研究,我提出了一个基于计时器的尝试,但在Safari中,它不会重复这个角色。我有一个菜单系统,按下箭头可以在列表中滚动,但是翻译动画和重复率不一样 var repeating = false; var repeatRateTimer = null; $( document ).b

目标是手动设置保持键的“重复率”

例如,当在文本框中按住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
} );
我可能把这整件事搞砸了…我试图重新创建一个简化版的。然而,我觉得必须有更好的方法来做到这一点。有什么想法吗

更新:

我们可以假设最终用户没有将他们的操作系统键盘重复率设置为大于我想要使用的速率(1000ms)。如果是的话,那么它应该回到它们的重复率,因为它不会一直触发按键事件。如果它不是(更可能的是,因为大多数人不修改它),那么我们将覆盖该行为,使其延迟指定的时间

请看以下内容。如果向下滚动到第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
事件的间隔(这是您想要的)。您可以使用
Keyboard
类实例的
addEventListener
方法添加事件侦听器:

var keyboard = new Keyboard(125); // fire key press 8 times a second.

keypress.addEventListener("keypress", 65, function () {
    // do something every time A is pressed
});
请注意,上面的类依赖于以下框架:。您可以看到上述脚本的工作演示。希望这有帮助

更新1:

你的工作在歌剧院不起作用。此外,第二个事件在Firefox中额外延迟500毫秒后触发,连续事件不会保持相同的间隔。另外,它不能同时处理多个关键事件。让我们纠正这个问题:

首先,我们需要为创建一个简单的脚本,以便在恒定的间隔后触发关键事件。我们使用以下代码片段创建一个
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);
    }
}
接下来,我们编写触发自定义
按键事件的逻辑。我们需要自定义事件,因为我们必须能够同时处理多个键:

(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);
间隔
设置为
1000
ms,但您可以更改。最后,要注册一个事件,我们需要:

window.addEventListener("keypressed", function (event) {
    document.body.innerHTML += event.keyCode + " (" + event.time + " ms)<br/>";
}, false);

使用上面的代码将消除您正在经历的短暂延迟,并允许同时为不同的键触发多个事件。

好吧,我找到了我的示例没有循环的原因。在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 );
}

我将保留此悬赏,以防有人可以改进此功能,或提供更好的替代方案。

如何制作自定义关键事件。您可以收听原始事件(keyup/keydown),如果它们超过时间条件,您将触发自定义事件。
这种方式的好处是,您不依赖计时器,而且它为您提供了更多的功能,因为您使用自定义事件(顺便说一句,如果您愿意,您可以跳过取消事件部分)。
下面是一个演示,看看我在说什么:
基本代码如下所示:

$(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');
        });
});
$(文档).ready(函数(){
var调度程序=$(窗口),
keyRate=1000,//ms
lastKeyEvent=0,
cancelEvent=函数(e){
var evt=e?e:window.event;
if(evt.stopPropagation)
evt.stopPropagation();
如果(evt.cancelBubble!=null)
evt.cancelBubble=真;
返回false;
};
调度员
.bind('keydown',函数(e){
var now=new Date().getTime();

if(now-lastKeyEvent这是一篇老文章,但我想与rxjs分享我当前的答案。我不得不用Javascript做一个俄罗斯方块游戏,我想更改按键重复延迟以获得更好的游戏性

实际上,我们不能覆盖操作系统特有的真正的keydown repeat delay属性。 但是,由于keyup和keydown事件,我们可以对其进行模拟

最后,我想出了这个(打字脚本):

function keyDown$(键:KeyboardKey):可观察{
从event(document'keydown').pipe(filter(event=>event.key==key))返回;
}
函数keyUp$(键:KeyboardKey):可观察{
从event(document'keyup').pipe(filter(event=>event.key==key))返回;
}
导出功能键按下$(键:键盘键):可见{
返回合并(keyDown$(键),keydup$(键)).pipe(
过滤器(event=>event.repeat===false),
开关映射(event=>(event.type=='keydown'?合并(of(event),timer(150,50)。管道(mapTo(event)):从不)
);
}
...
按键$('ArrowRight')。订阅({
下一步:(事件)=>{
...
}
});
JS版本:

函数keyDown$(键){
从event(document'keydown').pipe(filter(event=>event.key==key))返回;
}
函数keyUp$(键){
从event(document'keyup').pipe(filter(event=>event.key==key))返回;
}
导出功能键按下$(键){
返回合并(keyDown$(键),keydup$(键)).pipe(
过滤器(event=>event.repeat===false),
开关映射(event=>(event.type=='keydown'?合并(of(event),timer(150,50)。管道(mapTo(event)):从不)
);
}
...
按键$('ArrowRight')。订阅({
下一步:(事件)=>{
...
}
});
keyPressed$
函数将键盘键作为参数并返回一个可观察值。当相应的
$(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');
        });
});