psychopy.org | Reference | Downloads | Github

Experiment freezes during response screen

URL of experiment: attention_numerosity_study1 · GitLab (pavlovia.org)

attention_numerosity_study1 [PsychoPy] (pavlovia.org)

Description of the problem:

Hello,

Some of my participants (around 1/10 of them) reported that their experiment froze during a response screen. In this screen, I expect participants to enter some numbers using their keyboard and I print those numbers on the screen while they are typing. I present .mp3 files and also use a mouse component (before this problem occurs). I tried a thousand times and couldn’t replicate this problem. It doesn’t appear to be happening in a particular trial. I checked the developer tools and there isn’t any error (there are only some warnings that do not seem related to this issue).

The warnings I got were:

*The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page. *

[Deprecation] The ScriptProcessorNode is deprecated. Use AudioWorkletNode instead.

WARN unknown | setting the value of attribute: size in PsychObject: TextStim as: undefined

Because I wasn’t able to replicate it, I desperately asked participants who experienced this problem some questions. The only things that were common among the participants were 1) they were all windows users, 2) they had an external mouse or a keyboard plugged in (in addition to the touchpad or the internal keyboard of their laptops).

Here are some stuff I tried to replicate the problem and failed:

  1. Exiting and re-entering fullscreen
  2. Waiting for a long time to respond
  3. Pressing other keys before pressing a valid key
  4. Receiving notifications during the response screen
  5. Using a mouse on a windows laptop

I would be really happy if anyone had any ideas, or experienced something similar to this and found a solution.

Please could you show the code you use to accept the keyboard input and end the routine?

I am sorry in advance that this is very long and probably too complicated. I am using the builder with code components and in the end javascript looks like a mess.

var _key_resp_allKeys;
var resp_text;
var big_error;
var pressed_backspace;
var first_key;
var keyboard_responseComponents;
function keyboard_responseRoutineBegin(snapshot) {
  return function () {
    //------Prepare to start Routine 'keyboard_response'-------
    t = 0;
    keyboard_responseClock.reset(); // clock
    frameN = -1;
    continueRoutine = true; // until we're told otherwise
    // update component parameters for each repeat
    key_resp.keys = undefined;
    key_resp.rt = undefined;
    _key_resp_allKeys = [];
    resp_text = new visual.TextStim({"win": win, "text": "", "color": red, "units": "pix", "height": (1.3 * ang_pix)});
    big_error = new visual.TextStim({"win": win, "text": "13'ten b\u00fcy\u00fck bir say\u0131 girmeyiniz!", "pos": [0, (- 100)], "color": red, "units": "pix", "height": (1.3 * ang_pix)});
    resp_text.text = "";
    pressed_backspace = false;
    end_key_resp = false;
    first_key = true;
    key_resp.clearEvents();
    rt = 0;
    
    // keep track of which components have finished
    keyboard_responseComponents = [];
    keyboard_responseComponents.push(key_resp);
    
    for (const thisComponent of keyboard_responseComponents)
      if ('status' in thisComponent)
        thisComponent.status = PsychoJS.Status.NOT_STARTED;
    return Scheduler.Event.NEXT;
  }
}


var _pj;
var allkeys;
var quit_keys;
function keyboard_responseRoutineEachFrame(snapshot) {
  return function () {
    //------Loop for each frame of Routine 'keyboard_response'-------
    // get current time
    t = keyboard_responseClock.getTime();
    frameN = frameN + 1;// number of completed frames (so 0 is the first frame)
    // update/draw components on each frame
    
    // *key_resp* updates
    if (t >= 0.0 && key_resp.status === PsychoJS.Status.NOT_STARTED) {
      // keep track of start time/frame for later
      key_resp.tStart = t;  // (not accounting for frame time here)
      key_resp.frameNStart = frameN;  // exact frame index
      
      // keyboard checking is just starting
      psychoJS.window.callOnFlip(function() { key_resp.clock.reset(); });  // t=0 on next screen flip
      psychoJS.window.callOnFlip(function() { key_resp.start(); }); // start on screen flip
      psychoJS.window.callOnFlip(function() { key_resp.clearEvents(); });
    }

    if ((key_resp.status === PsychoJS.Status.STARTED || key_resp.status === PsychoJS.Status.FINISHED) && Boolean(end_key_resp)) {
      key_resp.status = PsychoJS.Status.FINISHED;
  }

    if (key_resp.status === PsychoJS.Status.STARTED) {
      let theseKeys = key_resp.getKeys({keyList: [' '], waitRelease: false});
      _key_resp_allKeys = _key_resp_allKeys.concat(theseKeys);
      if (_key_resp_allKeys.length > 0) {
        key_resp.keys = _key_resp_allKeys[_key_resp_allKeys.length - 1].name;  // just the last key pressed
        key_resp.rt = _key_resp_allKeys[_key_resp_allKeys.length - 1].rt;
      }
    }
    
    var _pj;
    function _pj_snippets(container) {
        function in_es6(left, right) {
            if (((right instanceof Array) || ((typeof right) === "string"))) {
                return (right.indexOf(left) > (- 1));
            } else {
                if (((right instanceof Map) || (right instanceof Set) || (right instanceof WeakMap) || (right instanceof WeakSet))) {
                    return right.has(left);
                } else {
                    return (left in right);
                }
            }
        }
        container["in_es6"] = in_es6;
        return container;
    }
    _pj = {};
    _pj_snippets(_pj);
    allkeys = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "backspace"];
    win_rect.draw();
    responses = key_resp.getKeys({"keyList": allkeys, "waitRelease": true, "clear": true});
    quit_keys = key_resp.getKeys({"keyList": ["space"], "waitRelease": false});
    if ((resp_text.text.length > 0)) {
        if ((Number.parseInt(resp_text.text) > 13)) {
            big_error.draw();
        } else {
            big_error.setAutoDraw(false);
        }
        for (var key, _pj_c = 0, _pj_a = quit_keys, _pj_b = _pj_a.length; (_pj_c < _pj_b); _pj_c += 1) {
            key = _pj_a[_pj_c];
            if ((key.name === "space")) {
                end_key_resp = (Number.parseInt(resp_text.text) <= 13);
            }
        }
    }
    if ((responses.length > 0)) {
        for (var key, _pj_c = 0, _pj_a = responses, _pj_b = _pj_a.length; (_pj_c < _pj_b); _pj_c += 1) {
            key = _pj_a[_pj_c];
            if ((key.name === "backspace")) {
                pressed_backspace = true;
                resp_text.text = resp_text.text.slice(0, (- 1));
            } else {
                if (_pj.in_es6(key.name, allkeys)) {
                    resp_text.text = (resp_text.text + key.name);
                    if (first_key) {
                        rt = key.rt;
                        first_key = false;
                    }
                }
            }
        }
    }
    resp_text.draw();
    
    // check if the Routine should terminate
    if (!continueRoutine) {  // a component has requested a forced-end of Routine
      return Scheduler.Event.NEXT;
    }
    
    continueRoutine = false;  // reverts to True if at least one component still running
    for (const thisComponent of keyboard_responseComponents)
      if ('status' in thisComponent && thisComponent.status !== PsychoJS.Status.FINISHED) {
        continueRoutine = true;
        break;
      }
    
    // refresh the screen if continuing
    if (continueRoutine) {
      return Scheduler.Event.FLIP_REPEAT;
    } else {
      return Scheduler.Event.NEXT;
    }
  };
}


function keyboard_responseRoutineEnd(snapshot) {
  return function () {
    //------Ending Routine 'keyboard_response'-------
    for (const thisComponent of keyboard_responseComponents) {
      if (typeof thisComponent.setAutoDraw === 'function') {
        thisComponent.setAutoDraw(false);
      }
    }
    psychoJS.experiment.addData('key_resp.keys', key_resp.keys);
    if (typeof key_resp.keys !== 'undefined') {  // we had a response
        psychoJS.experiment.addData('key_resp.rt', key_resp.rt);
        }
    
    key_resp.stop();
    resp_text.setAutoDraw(false);
    thisExp.addData("response", Number.parseInt(resp_text.text));
    thisExp.addData("response_rt", rt);
    thisExp.addData("pressed_backspace", pressed_backspace);
    
    // the Routine "keyboard_response" was not non-slip safe, so reset the non-slip timer
    routineTimer.reset();
    
    return Scheduler.Event.NEXT;
  };
}


I’d find it much easier to read the Python code in your Auto translated code compoents. However, I spotted this which seems redundant since it keeps getting reset to empty.

Thank you very much. I am definitely going to check if that’s something I’ve written.

Here is the python code. I also generated a keyboard component in gui that this code uses, which is called key_resp. It begins at t=0, ends when $end_key_resp.

Begin Routine

resp_text = visual.TextStim(win=win, text='', color=red, units='pix', height=1.3 * ang_pix)
big_error = visual.TextStim(win=win, text="13'ten büyük bir sayı girmeyiniz!", pos = [0, -100], color = red, units='pix', height=1.3 * ang_pix)
resp_text.text = ''
pressed_backspace = False
end_key_resp = False
first_key = True
key_resp.clearEvents()
rt = 0

Each Frame

allkeys = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'backspace']

win_rect.draw()

responses = key_resp.getKeys(keyList=allkeys, waitRelease=True, clear=True)
quit_keys = key_resp.getKeys(keyList=['space'], waitRelease=False)
if len(resp_text.text) > 0:
    if int(resp_text.text) > 13:
        big_error.draw()
    else:
        big_error.setAutoDraw(False)
        
    for key in quit_keys:
        if key.name == 'space':
            end_key_resp = int(resp_text.text) <= 13
   
   
if len(responses) > 0:
    for key in responses:
        if key.name == 'backspace':
            pressed_backspace = True
            resp_text.text = resp_text.text[0:-1]
        elif key.name in allkeys:
            resp_text.text = resp_text.text + key.name
            if first_key:
                rt = key.rt
                first_key = False
        
resp_text.draw()

End Routine

resp_text.setAutoDraw(False)
thisExp.addData('response', int(resp_text.text))
thisExp.addData('response_rt', rt)
thisExp.addData('pressed_backspace', pressed_backspace)

I don’t think you should be using getKeys for a keyboard component.

I would use keys=event.getKeys()

if ‘space’ in keys:

elif len(keys):

Thank you sir, I always felt that this was a terrible way to collect keyboard responses but didn’t know the psychopy way to do things.

Can this be causing the problem? More specifically, can this cause an unsystematic error? I am asking because this is working for most of my participants, and even when it doesn’t when participants re-run the experiment they can run it without any problems.