2

I was wondering if there was a way to restrict document.onkeydown to once per 1000ms (1s).

Here is my code:

document.onkeydown = function(e) {
    switch (e.keyCode) {
        case 37:
            console.log("left");
            break;
        case 38:
            console.log("up");
            break;
        case 39:
            console.log("right");
            break;
        case 40:
            console.log("down");
            break;
    }
};

So if a user hits the down arrow (case 40), it will print down to the console.

I was wondering if I could restrict it, so if the user hits the down arrow multiple times within a second, it will only register once, and wont queue up.

MaliciouZzHD
  • 49
  • 1
  • 12
  • A good question on this topic with a very helpful answer and a lot of useful links related to JavaScript can be found under [Difference Between throttling and debouncing a function](https://stackoverflow.com/questions/25991367/difference-between-throttling-and-debouncing-a-function/25991510#25991510) – Peter Seliger Mar 11 '18 at 12:11

3 Answers3

3

I would do something like this:

document.onkeydown = function(e) {
    let lastEvent = null,
        lastPressesTimestamp = null
    if(e.keyCode === lastEvent && lastPressesTimestamp && (Date.now() - lastPressesTimestapm) < 1000){
        return
    } else{
        lastEvent = e.keyCode, lastPressesTimestamp = Date.now()
    }
    switch (e.keyCode) {
        case 37:
            console.log("left");
            break;
        case 38:
            console.log("up");
            break;
        case 39:
            console.log("right");
            break;
        case 40:
            console.log("down");
            break;
    }
};
jkofron.e
  • 5,043
  • 1
  • 17
  • 16
Anurag Awasthi
  • 6,115
  • 2
  • 18
  • 32
1

Try this :

function debounce (fn, delay) {
    var timer = null;

    return function () {
        var context = this, args = arguments;
        clearTimeout(timer);
        timer = setTimeout(function () {
            fn.apply(context, args);
        }, delay);
    };
};

document.onkeydown = debounce(function(e) {
    switch (e.keyCode) {
        case 37:
            console.log("left");
            break;
        case 38:
            console.log("up");
            break;
        case 39:
            console.log("right");
            break;
        case 40:
            console.log("down");
            break;
    }
}, 1000);

UPDATE (remove 1s delay before console write key) :

function debounce (fn, delay) {
    var timer = null;
    var during = null;

    return function () {

        var context = this, args = arguments;
        if(!during) {
           fn.apply(context, args);
           during = 1;
        }

        clearTimeout(timer);
        timer = setTimeout(function () {
            during = null;
        }, delay); 

    };
};

UPDATE 2 (when user push key for long time then every one second console writs key)

function debounce (fn, delay) {
    var timer = null;
    var start = + new Date(); // Unix timestamp

    return function () {
        var current = + new Date();

        if(current-start > delay) {
           fn.apply(this, arguments);
           start = current;
        }
    };
};

working fiddle HERE

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
0

A good question on this topic with a very helpful answer and a lot of useful links related to JavaScript can be found at SO at Difference Between throttling and debouncing a function.

There are a bunch of well established libraries like e.g underscore or lodash that handle throttle and/or debounce very well.

If there was a Function.prototype based implementation of throttle / debounce a working solution to the OP's Q might look like this ...

// example code

function logKeyDown(evt) {
  var
    keyCode = evt.keyCode,
    value   = {

      37: 'left',
      38: 'up',
      39: 'right',
      40: 'down'

    }[keyCode] || keyCode;

  console.log("logKeyDown : ", value);
}

var keyEventHandler = logKeyDown.throttle(1000);



// UI helper code

function registerKeyLogger() {
  elmRegister.disabled    = true;
  elmDeregister.disabled  = false;

  window.addEventListener("keydown", keyEventHandler, false);

  console.log('\n');
  console.log('+++ keylogger registered +++');
  console.log('+++ press any key - inspect log +++');
}
function deregisterKeyLogger() {
  elmRegister.disabled    = false;
  elmDeregister.disabled  = true;

  window.removeEventListener("keydown", keyEventHandler);

  console.log('\n');
  console.log('+++ key-logger has been deregistered +++');
}

var
  elmRegister   = document.getElementById('register-key-logger'),
  elmDeregister = document.getElementById('deregister-key-logger');

if (elmRegister && elmDeregister) {
  elmRegister.disabled = false;
  elmRegister.addEventListener('click', registerKeyLogger);
  elmDeregister.addEventListener('click', deregisterKeyLogger);
}
.as-console-wrapper { max-height: 100%!important; top: 40px; }
<script>(function(b,w,p,h){h=h.prototype;var q=function(a){return"function"==typeof a&&"function"==typeof a.call&&"function"==typeof a.apply},x=b.isFinite,y=b.parseInt,k=b.setTimeout,r=b.clearTimeout,z=q(p.now)&&p.now||function(){return(new p).getTime()},t=w.max,v=function(a){return x(a=y(a,10))&&a||0};h.throttle=function(a,u,d){d=null!=d&&d||null;a=t(v(a),0)||200;u=!!u;var e=this,l,c,f,g,b,m,n=function(){f=g;e.apply(b,m)};return q(e)&&function(){r(l);b=d||this;m=arguments;g=z();f?(c=g-f,u?c>=a&&n():l=k(n,t(a-c,0))):n()}||e};h.debounce=function(a,b,d){d=null!=d&&d||null;a=t(v(a),0)||100;b=!!b;var e=this,l,c,f,g,h=function(){c=null},m=function(){c=null;e.apply(f,g)},n=function(){l=k(h,a);e.apply(f,g)};c=null;return q(e)&&function(){f=d||this;g=arguments;c?(r(l),r(c),c=k(m,a)):c=b?k(n,0):k(m,a)}||e}})(window||global||this,Math,Date,Function);</script>

<button id="register-key-logger" disabled="disabled">register key logger</button>
<button id="deregister-key-logger" disabled="disabled">deregister key logger</button>
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37