Pavlovia not recognizing 'backspace' key

I have an experiment where I have people type their name. I want then to be able to delete letters (in case they typed it wrong). Locally, on PsychoPy, my code works. When I try to run it on Pavlovia, it longer does. When I look at the datafile, even though, I pressed ‘backspace’, the key is not in the datafile, which is why I think Pavlovia is not recognizing it.

Here is the javascript code I am using.

if(keyResp.keys != undefined && keyResp.keys.length > last_len) {
    last_len = keyResp.keys.length
    key_list.push(keyResp.keys.pop())
    if(key_list.indexOf("backspace") != -1) {
        if (key_list.length > 0) {
            key_list.pop();
        }
    }
    else
    if(key_list.indexOf("return") != -1) {
        key_list.pop(); 
        if (key_list.length >= 2) {
            continueRoutine = false;
        }
    }
    else 
    if(key_list.indexOf("space") != -1) {
    key_list.pop();
    key_list.push(' ');
}
    while (key_list.length > maxDigits) {
        key_list.pop();
    }
    respDisplay = key_list.join("");
}

Please help :slight_smile:

I’m using ‘N/A’ to represent backspace (and other keys that no longer register in keyboard components online) and shift N/A for ?

Textbox components have come a long way but I needed to disable spell check.

Have a look at my key check online demo to see the available keys.

Here’s my Each Frame code for a narrative test.

if key_all.keys:
        if len(key_all.keys) > nKeys:
            if key_all.keys[-1] == 'space' or key_all.keys[-1] == 'return':
                thisExp.nextEntry()
                thisExp.addData('WordTime',myClock.getTime()-wordTime)
                wordTime = myClock.getTime()
                thisExp.addData('Word',oldText[wordPos:])
                thisExp.addData('BackspaceCount',backspaceCount)
                thisExp.addData('TypingTime',myClock.getTime())
                backspaceCount = 0
                if key_all.keys[-1] == 'return':
                    newText += '\n'
                    wordPos = nCharacters + 2
                    allPos.append(wordPos-1)
                else:
                    newText += ' '
                    wordPos = nCharacters + 1
                    allPos.append(wordPos)
            elif key_all.keys[-1] == 'N/A':
                if upperCase:
                    newText += '?'
                    upperCase = False
                elif nCharacters > 0:
                    newText = newText[:-1]
                    if wordPos >= nCharacters:
                        wordPos = allPos.pop()
            elif key_all.keys[-1] == 'backspace':
                 if nCharacters > 0:
                    newText = newText[:-1]
                    if wordPos >= nCharacters:
                        wordPos = allPos.pop()
            elif key_all.keys[-1] == 'left':
                 if nCharacters > 0:
                    newText = newText[:-1]
                    if wordPos >= nCharacters:
                        wordPos = allPos.pop()
            elif key_all.keys[-1] == 'lshift' or key_all.keys[-1] == 'rshift':
                if upperCase:
                    upperCase = False
                else:
                    upperCase = True
            elif key_all.keys[-1] == 'period':
                if upperCase:
                    newText += '>'
                    upperCase = False
                else:
                    newText += '.'
            elif key_all.keys[-1] == 'comma':
                if upperCase:
                    newText += '<'
                    upperCase = False
                else:
                    newText += ','
            elif key_all.keys[-1] == 'semicolon':
                if upperCase:
                    newText += ':'
                    upperCase = False
                else:
                    newText += ';'
            elif key_all.keys[-1] == 'apostrophe':
                if upperCase:
                    newText += '@'
                    upperCase = False
                else:
                    newText += '\''
            elif key_all.keys[-1] == 'minus':
                if upperCase:
                    newText += '_'
                    upperCase = False
                else:
                    newText += '-'
            elif key_all.keys[-1] == 'grave':
                if upperCase:
                    newText += '|'
                    upperCase = False
                else:
                    newText += '\''
            elif len(key_all.keys[-1]) == 1:
                if upperCase:
                    if key_all.keys[-1] == '1':
                        newText += '!'
                    elif key_all.keys[-1] == '2':
                        newText += '"'
                    elif key_all.keys[-1] == '3':
                        newText += '£'
                    elif key_all.keys[-1] == '4':
                        newText += '$'
                    elif key_all.keys[-1] == '5':
                        newText += '%'
                    elif key_all.keys[-1] == '6':
                        newText += '^'
                    elif key_all.keys[-1] == '7':
                        newText += '&'
                    elif key_all.keys[-1] == '8':
                        newText += '*'
                    elif key_all.keys[-1] == '9':
                        newText += '('
                    elif key_all.keys[-1] == '0':
                        newText += ')'
                    else:
                        newText += key_all.keys[-1].upper()
                    upperCase = False
                else:
                    newText += key_all.keys[-1]
           # nSpaces = len(key_all.keys)
            nKeys += 1

nCharacters = len(newText)
if oldLength > nCharacters:
    backspaceCount += 1
oldLength = nCharacters
if cursorCounter >= 30:
    if cursorVariable=='|':
        cursorVariable=' '
    else:
        cursorVariable='|'
    cursorCounter=0
    oldText = '|'
cursorCounter+=1
if newText != oldText:
    textbox_3.text = newText+cursorVariable
    oldText = newText
if timeStarted == True:
    newClock=600-myClock.getTime()   
    if newClock <= 0:
        continueRoutine = False

Hi @wakecarter ,
Just to clarify, does this all mean that one can no longer use Backspace as a key press response to, for example, end a Routine? Is there a plan to re-implement this functionality or is there an important reason that it is no longer possible? We use this in instruction trials, to make sure our participants know how to correct their typed answers, so it is a shame to lose this option.
And the code you shared above is python, right? Do you have the equivalent for psychoJS by any chance?
Thanks and best wishes,
Donna

I’m using this code to register the backspace. I’ll nudge my bug report to see if there’s any progress on this.

My Python code goes into an Auto->JS code component to make the PsychoJS code.

1 Like

URL of experiment: AnkerEffekt [PsychoPy]

Description of the problem: Backspace does not work online

Hello

I have a simple anchor-experiment in which I use the following code to collect the responses from the participants.

Python Begin routine

text.text = ''
event.clearEvents('keyboard')

Python Each frame

keys = event.getKeys()

if len(keys):
    if ('backspace' in keys or 'N/A' in keys) and len(text.text):
        text.text = text.text[:-1]
    elif ('return' in keys or 'num_enter' in keys) and text.text != '':
        continueRoutine = False
    elif '1' in keys or 'num_1' in keys:
        text.text = text.text+'1'
    elif '2' in keys or 'num_2' in keys:
        text.text = text.text+'2'
    elif '3' in keys or 'num_3' in keys:
        text.text = text.text+'3'
    elif '4' in keys or 'num_4' in keys:
        text.text = text.text+'4'
    elif '5' in keys or 'num_5' in keys:
        text.text = text.text+'5'
    elif '6' in keys or 'num_6' in keys:
        text.text = text.text+'6'
    elif '7' in keys or 'num_7' in keys:
        text.text = text.text+'7'
    elif '8' in keys or 'num_8' in keys:
        text.text = text.text+'8'
    elif '9' in keys or 'num_9' in keys:
        text.text = text.text+'9'
    elif '0' in keys or 'num_0' in keys:
        text.text = text.text+'0'

Python End Routine

thisExp.addData("Antwort", text.text)

While this works offline, it does not work online.
PsychoJS Begin routine

text.text = "";
psychoJS.eventManager.clearEvents("keyboard");

PsychoJS Each frame

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);
keys = psychoJS.eventManager.getKeys();
if (keys.length) {
    if (((_pj.in_es6("backspace", keys) || _pj.in_es6("N/A", keys)) && text.text.length)) {
        text.text = text.text.slice(0, (- 1));
    } else {
        if (((_pj.in_es6("return", keys) || _pj.in_es6("num_enter", keys)) && (text.text !== ""))) {
            continueRoutine = false;
        } else {
            if ((_pj.in_es6("1", keys) || _pj.in_es6("num_1", keys))) {
                text.text = (text.text + "1");
            } else {
                if ((_pj.in_es6("2", keys) || _pj.in_es6("num_2", keys))) {
                    text.text = (text.text + "2");
                } else {
                    if ((_pj.in_es6("3", keys) || _pj.in_es6("num_3", keys))) {
                        text.text = (text.text + "3");
                    } else {
                        if ((_pj.in_es6("4", keys) || _pj.in_es6("num_4", keys))) {
                            text.text = (text.text + "4");
                        } else {
                            if ((_pj.in_es6("5", keys) || _pj.in_es6("num_5", keys))) {
                                text.text = (text.text + "5");
                            } else {
                                if ((_pj.in_es6("6", keys) || _pj.in_es6("num_6", keys))) {
                                    text.text = (text.text + "6");
                                } else {
                                    if ((_pj.in_es6("7", keys) || _pj.in_es6("num_7", keys))) {
                                        text.text = (text.text + "7");
                                    } else {
                                        if ((_pj.in_es6("8", keys) || _pj.in_es6("num_8", keys))) {
                                            text.text = (text.text + "8");
                                        } else {
                                            if ((_pj.in_es6("9", keys) || _pj.in_es6("num_9", keys))) {
                                                text.text = (text.text + "9");
                                            } else {
                                                if ((_pj.in_es6("0", keys) || _pj.in_es6("num_0", keys))) {
                                                    text.text = (text.text + "0");
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

PsychoJS End Routine

psychoJS.experiment.addData("Antwort", text.text);

Thanks a lot for your help.

Jens

I’m sorry, but we don’t have a fix for this yet, other than the workaround in your code of assuming ‘N/A’ means backspace.

URL of experiment: https://run.pavlovia.org/LIPLab/pas_24b_prolific

Description of the problem:
Hi everyone, I’ve read the previous posts about the backspace key not working when the experiment is running online and still have not been able to solve my problem. I am running Psychopy v 2024.1.4. my experiment (code below) needs to collect typed keystrokes and their times. When running the experiment locally, all keys (including shift, spacebar… are recorded and show up on the screen). When running online, the only problem I have is with the backspace key, it is not recorded in the dataset and letters are not removed from the screen.

I tried an earlier suggestion of indexing backspace as ‘N/A’, but it did not seem to do the trick. I also tried using ‘delete’ instead of ‘backspace’.

Two quick notes about my code: First, I have experimental conditions so that some participants see the letter they typed on the screen, and some see “*”. Second, the javascript code is just what is automatically generated by PsychoPy.

thesekeys=event.getKeys()
n = len(thesekeys)
i = 0
frameNo = frameNo + 1

if frameNo < 5:
inputText = “”

while i < n:

#Hitting return ends trial
if thesekeys[i] == 'return':
    continueRoutine = False
    break 

#Hitting escape quits the experiment
elif thesekeys[i] == 'escape':
    core.quit()
    
#spacebar inserts blank space
elif thesekeys[i] == 'space':
    inputText += " "
    thisExp.addData("typingRT", typingclock.getTime())
    thisExp.addData("letterTyped", thesekeys[i])
    i+=1
    thisExp.nextEntry()
    
#shift raises "shift flag"    
elif thesekeys[i] == 'lshift' or thesekeys[i] == 'rshift' or thesekeys[i] == 'SHIFT':
    shiftFlag = True
    thisExp.addData("typingRT", typingclock.getTime())
    thisExp.addData("letterTyped", thesekeys[i])
    i+=1
    thisExp.nextEntry()

#Input the letter (capitalized or not)
else: 
    #handle the delete key, indexed as 'N/A'
    if thesekeys[i] == 'N/A':
        inputText = inputText[:-1]
        thisExp.addData("typingRT", typingclock.getTime())
        thisExp.addData("letterTyped", thesekeys[i])
        i+=1       
        thisExp.nextEntry()
    #Input and record capitalized letter
    else: 
        if shiftFlag == True and mask == 0:
            inputText += thesekeys[i].upper()
        elif shiftFlag == False and mask == 0:
            inputText += thesekeys[i]
        elif mask == 1:
            inputText += "*"
      
        thisExp.addData("typingRT", typingclock.getTime())
        thisExp.addData("letterTyped", thesekeys[i])
        shiftFlag = False

    i+=1
    thisExp.nextEntry()

Hello

‚N/A‘ does not help. I switched to the textbook-component which seems to working as expected. This is only possibly because I do not need the RT for each keystroke but just the response.

Best wishes Jens

Why didn’t N/A help?

Using an editable textbox component you can also check each frame to see if the contents have changed in order to get reaction times for each letter.

Hello

I do not need RTs. Thanks a lot.

I have no idea why ‘N/A’ did not help. I had to get the programme up and running, so I did not look into it any further. I will have more time next week.

Best wishes Jens