psychopy.org | Reference | Downloads | Github

Logging duration of keypress to end routine

Hi all,

I have been trying (and failing) to get end-on-key-release functionality to work on Pavlovia. I have searched the forum but have not been able to find or adapt any past question to my specific use-case.

This is the functionality I am trying to achieve online.

I am able to get this to work perfectly in builder, but I am unable to replicate the effect on Pavlovia.

I am using the following Auto>JS code in the Each Frame tab:

var continuing, kb, remainingKeys;
kb = new core.Keyboard({psychoJS: psychoJS, clock: new util.Clock(), waitForStart: true})
continuing = true;
while (continuing) {
    remainingKeys = kb.getKeys({"waitRelease": true});
    if (remainingKeys) {
        for (var key, _pj_c = 0, _pj_a = remainingKeys, _pj_b = _pj_a.length; (_pj_c < _pj_b); _pj_c += 1) {
            key = _pj_a[_pj_c];
            if ((key.name === "space")) {
                continuing = false;
            }
        }
    }
}

This is a link to the gitlab, the experiment is currently piloting and I am not sure if there is a way to make it public without using credits.

Currently, the experiment shows the first frame “Before Text” and allows for no keypresses or really any interaction without force quitting.

Again, the functionality I am looking for is as follows:

Show Square > Wait for keypress and release > Show Square > repeat

Thank you for your time!

Hi David,

I managed to build an experiment that does what you’re after. It’s bit hacky though, but it works. Here is the link: https://gitlab.pavlovia.org/tpronk/demo_keyup

Below some notes on how I got here:

  • Looking a the source code of getKeys(), I noticed that waitRelease == true didn’t actually do anything. https://psychopy.github.io/psychojs/core_Keyboard.js.html#line158
  • I did notice there were some other functions that could be useful, namely getEvents(), which returns all keyboard events since the start of the routine and clearEvents(), which empties it again.
  • I built an algorithm that loops through the events returned by getEvents(), looks for keydown event, followed by a keyup event. If both are present, it calculates how much time passed between them and ends the routine
  • To get this to work I needed to configure the Keyboard component in a particular way: Force end of Routine disabled, and the key you’re looking for (‘space’) should not be in the list of allowedKeys.

Hope this helps!

Best, Thomas

1 Like

Hi Thomas,

First, thank you so much for taking the time to look into this and create a solution! I had seen that there were issues using the keyboard library and I didn’t really know where to go from there.

Trying out the experiment that you’ve linked ends only when I press escape is that correct? You will see several (sorry!) new data files from me. If I was looking to adapt this into a:

show square>press and release space > repeat

Would I just add a square routine before hand?

I don’t know what the etiquette is on forking code so I wanted to make sure I touched base with you!

Again, thank you very much for the assistance!

EDIT I just made some changes to an existing template using your code and it seems to be working perfectly!

This is a link to the template. The only thing I changed was adding the duration as output to the .csv.

I plan on adding this into one of the experiments I am working on, and I will make sure to leave your name in the code! Thank you!!! :smile:

Happy to hear this helped you out. I work as a software developer with the PsychoJS team, so feel free to do whatever you’d like with it :). We should also implement the waitRelease in a future version, so I made an issue for that on our GitHub. https://github.com/psychopy/psychojs/issues/198

Good luck with the rest of your study!

1 Like

Hi David,

I’ve been struggling with the same issue for a while. Unfortunately, it seems that the template you provided in your link isn’t available anymore. Could you please offer some more details of your solution, or maybe share your script again?

I’m trying to design a task as follows: The participant has to keep pressed the spacebar for a certain duration. Then, I would like to end the routine at the moment the key is released. I’ve come up with a solution that works for builder, but it doesn’t work online… Could you help me, please?

Thank you for your time!

Hi Nicolas,

Hmm, I will try and make the template active again. In my example I had the following routines:

before > start2 > after

before contains: a text element that lasts for one second and says “before text”

start2 contains: a keyboard component and a code snippet
The keyboard component is:

  1. set to accept ‘y’ and ‘n’ as responses
  2. NOT force the end of the routine
  3. Store all keys

The code snippet has the following in each tab:

  1. begin routine - window.kb = kb;
  2. each frame -
let keyEvents = kb.getEvents();
if (keyEvents .length > 0) {
    let keydownTimestamp;
    let keyupTimestamp;
    let i = 0;
    for (; i < keyEvents.length; i++) {
      if (keyEvents[i].pigletKey === 'space' && keyEvents[i].status === Symbol.for('KEY_DOWN')) {
        //console.log('found keydown at event ' + i);
        keydownTimestamp = keyEvents[i].timestamp;
       break;
      }
    }
    for (; i < keyEvents.length; i++) {
      if (keyEvents[i].pigletKey === 'space' && keyEvents[i].status === Symbol.for('KEY_UP')) {
        //console.log('found keyup at event ' + i);
        keyupTimestamp = keyEvents[i].timestamp;
        break;
      }
    }
    if (keydownTimestamp !== undefined && keyupTimestamp !== undefined) {
        console.log('duration ' + (keyupTimestamp - keydownTimestamp));
        kb.clearEvents();
        continueRoutine = false;
    }
}

After text contains: a text element that lasts for one second and says “after text”

This seems to only work once deployed in Pavlovia. Please let me know if this helps!

2 Likes

Hi David, sorry for the delay, I was struggling a bit to adapt it to my specific case, but it really helped! Completely solved my problem, thank you so much!

1 Like

I’m happy to type it out, but it is all @thomas_pronk!

2 Likes