Search code examples
javascriptkeyup

How to detect when all keys are released


The following code is supposed to measure how long a key (or more keys) was pressed.

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>

Is there any way to change the window.onkeyup function so that it makes the output log only when ALL keys are released?

Example:

10:00:00 - I press A and hold it

10:00:05 - I press B and hold it

10:00:20 - I press C and hold it

10:00:22 - I release A

10:00:24 - I release B

10:00:30 - I release C

Current code output:

26-2-2021 10:00:22 - Key(s) pressed for 22 seconds

26-2-2021 10:00:24 - Key(s) pressed for 2 seconds

26-2-2021 10:00:30 - Key(s) pressed for 6 seconds

Expected output:

26-2-2021 10:00:30 - Key(s) pressed for 30 seconds

Thank you for your help.


Solution

  • First of all, you should do pressed[e.code], not pressed[e], as this e object value will just stringify to [object KeyboardEvent], and so you assign to just one and the same property, on each keyboard event.

    To only report when all keys are up, keep track of a count and of the time the first key was pressed:

    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>

    Note that this is not completely bullet proof. If someone focusses another window and changes which keys are pressed before returning, these changes will not fire the events.