psychopy.org | Reference | Downloads | Github

Press and Hold Key to Move Slider

URL of experiment:
run: https://pavlovia.org/run/djangraw/mmi-survey-task/html/
code: https://gitlab.pavlovia.org/djangraw/mmi-survey-task/tree/master

Description of the problem:
We would like to have subjects rate their mood using a keyboard-operated slider. Ideally, they could press and hold the left or right arrow to make the slider’s marker move smoothly along the scale. However, I am having trouble implementing this with the onkeydown listener described here.

Here is the code I’m using (in a “begin experiment” code pane) to try to manipulate a slider called “currentSlider”:

// Declare constants
step = 0.05; // distance for short press
holdDur = 50; // ms before considered "held"
releaseDur = 200; // ms before considered "released"
speed = 0.0004; // distance per ms

// Initialize variables
tPressed = 0;
tLast = 0;
startPoint = 0.5;

// Set KeyHold function to run whenever key is currently pressed
document.onkeydown = KeyHold;

// Declare key-hold function for slider
function KeyHold(){
    // if currentSlider is inactive, do not continue
    if ((currentSlider === null) || (currentSlider.getAutoDraw() == false)) {
        return;
    }
    
    // Get ID of key pressed
    var KeyID = event.keyCode;
    
    // get current time
    var d = new Date();
    var tNow = d.getTime(); // in ms
    console.log("tNow-tLast = " + (tNow-tLast));
    // If it has been too long, consider this a new press and update tPressed
    if ((tNow-tLast)>releaseDur) {
        tPressed = tNow;
        startPoint = currentSlider.markerPos;
    }
    // Update tLast
    tLast = tNow;
    // Update press duration
    var pressDur = Math.max(tNow-tPressed-holdDur,0);
    
    // Move slider
    if (KeyID==37) { //left
        // move slider left
        currentSlider.markerPos = startPoint - step - pressDur*speed;
    } else if (KeyID==39) { //right
        // move slider right
        currentSlider.markerPos = startPoint + step + pressDur*speed;
    } else if (KeyID==32) { //space
        // lock in choice 
        var RT = currentSlider._responseClock.getTime()
        currentSlider._recordRating(currentSlider.markerPos,RT);
        //console.log("rating: " + currentSlider.getRating());
    }
    
    // Enforce limits on rating
    if (currentSlider.markerPos < 0) {
        currentSlider.markerPos = 0.0;
    } else if (currentSlider.markerPos > 1) {
        currentSlider.markerPos = 1.0;
    }
}

The latest problem I’m having is that the press-and-hold-arrow-key movement is choppy-looking - it seems to update every 83ms. I would also like to disable mouse input to force subjects to use the keyboard. Debugging help is appreciated, but I’m also just curious if anyone else has had luck with a keyboard-operated slider.