psychopy.org | Reference | Downloads | Github

UnicodeDecodeError

Hi. I make an experiment in psychopy and I want participants to type answers using the keyboard. The problem is that the language of the experiment is not English, and the responses should be written in Cyrilic font, but it works only with Latin script.
Are there any solutions?

1 Like

There are absolutely solutions, but you’ll have to give more information for us to know how to help you.

But the first step is, whenever you’re going to have a python string that contains a non-ASCII character (a character not found on an English keyboard), you should put a lowercase u in front of it to make it a unicode object:

#not good, will break
bad = 'çõøk'

# better, hopefully won't break
good = u'çõøk'

There are other places things can go wrong, but start with this and maybe it will be as simple as that.

1 Like

Thank you so much! It really works!
And I have one more question. Do I have to write all the letters of the keyboard in the code like

elif Keys[i] == ('d'):
        inputText += (u'ф')

or can I use smth like a exel table with all the letters and their ‘translation’ ?

You could create a Python dictionary:

key_table = {'d' : u'ф',
             'e' : u'ø'} # etc (with the actual values)

and then something like:

inputText += key_table[Keys[i]] # look up the equivalent key from the dictionary

But is that actually necessary? What if you set your keyboard in the OS language settings to be Russian: won’t you get the Cyrillic keys you want directly?

EDITED to fix typo picked up by @daniel.riggs1

Thank you, I’ll try it!
Actually, my keyboard had been in Russian before, but PsychoPy just doesn’t let to type in that language, unfortunately. That is why I decided to try to write a ‘translator’ for it.

It’s probably best if you stick to the Python primitives and use Unicode and libraries, but if I’m understanding what you want to do correctly, this (http://stackoverflow.com/questions/14173421/use-string-translate-in-python-to-transliterate-cyrillic/14173535#14173535) is probably among your better bets.

1 Like

Keep in mind that the keys that are sent could be different between machines ( so @Michael , sometimes it may indeed be necessary). For one poster on this forum, even though her system language was in Turkish, the key names received by pyglet were like a US keyboard for her Mac, but the lab computers were sending Turkish key names.

So @AnnArt , if I were you, I would make sure to test the machines you’re going to use. If you do have to “translate” the keys, @Michael’s suggestion of the dictionary is the way I would go. For the Turkish researcher I mentioned, we added a drop down in the Experiment Info dialog at the beginning of the experiment, so that she could change which keyboard layout the experiment would use.

Later today when at a computer, if you want I can share the typing solution we came up with for her.

1 Like

@tahabi, thank you, that topic is close to mine. I tried installing CyrTranslit, but it doesnt work (I guess, I do something wrong), unfortunately.
@daniel.riggs1, the Russian keys definately don’t match my experiment now, so I need to write them myself. I tried this one from Michael

key_table = {'d' : u'ф',
             'e' : u'у'} 
inputText += key_table(Keys[i])

but PsychoPy says “IndentationError: unident doesn’t match any outer indentation level”.

Actually, I’m not very familiar with PsychoPy and especially with Python, that’s why I suppose, that the problem is that I don’t what and where I should write.

About the indentation error, since python relies on indentation (how much space there is from the left side), there seems to be some mistake for where you have entered this code. It may need to be indented more or less (and make sure the file uses only spaces or only tabs for indentation! Don’t mix them. When copy-pasting, I would delete the leading spaces and add them back myself to make sure.) Michael was giving you an example of things you can do, but you have to know where to put this in your code.

About that, basic posting etiquette is that if you want help with an error, you should include the entire text of the error, otherwise we have to answer in very general terms. Also, it is best to include some code, but it should be a minimal working example: the absolute smallest amount of working code that demonstrates your problem.

But actually I think the line should be this, there’s a small typo (notice the brackets instead of parentheses):

inputText += key_table[Keys[i]]

Read some tutorials on python dictionaries so that you know what is happening, like this one, though you may prefer something in Russian. Sorry, I’m not sure how much coding experience you have, but if you’re brand new, working with the Builder interface and adding code components would probably be a softer introduction.

And again if I get some time later today, I’ll give you a small working example that I suspect would be just what you are looking for.

2 Likes

Thanks!
English tutorials are OK! I’ll try to use that one you suggest.
Right now the error is as follows

inputText += key_table[Keys[i]]
IndexError: string index out of range

and there is nothing more.
the code is like this

Each Frame:
n= len(Keys)
i = 0
key_table = {'d' : u'ф',
                   'e' : u'у'}
inputText += key_table[Keys[i]]

and yet I need to store correct answers, but it’s also impossible right now, because they are in Cyrilic script, so PsychoPy can’t use them.

Thanks to @daniel.riggs1 for picking up the error.

The problem you are getting now is that the dictionary only has two entries (for the ‘d’ and ‘e’ keys). I’m guessing you tried typing something other than ‘d’ or ‘e’ and so the dictionary look-up failed, as an entry wasn’t defined for whatever key you pushed.

As I’m not familiar with Russian, I didn’t try to provide a full set of options (and even my suggestion for an equivalent to the ‘e’ key was a random symbol). You will need to fill in all the other needed entries yourself, perhaps based on the useful link @tahabi provided.

You can protect yourself from not defining all entries like this:

if Keys[i] in key_table.keys(): # only if an equivalent has been defined
    inputText += key_table[Keys[i]]

i.e. even if you define all the letter equivalents you want, a person might push some other sort of key (like alt, shift, or ctrl), so this would allow those to be excluded and not cause an error when looking up the dictionary.

Also, the dictionary should just be created once (i.e. shift that to the Begin experiment tab of your component). There is no need to recreate it on every frame.

1 Like

Thanks!
I tried this one

if Keys[i] in key_table.keys(): # only if an equivalent has been defined
    inputText += key_table[Keys[i]]

and even when I try to respond using a letter defined in the dictionary, the error is as follows:
if Keys[i] in key_table.keys(): # only if an equivalent has been defined
IndexError: list index out of range

The problem there is your value for i, which is exceeding the number of entries in the list Keys.

I don’t know how you are creating/incrementing that index, so can’t help without seeing the relevant code.

I have this code in Each Frame:


n= len(theseKeys)
i = 0

while i < n:

    if theseKeys[i] == 'return':
        # pressing RETURN means time to stop
        continueRoutine = False
        break

    elif theseKeys[i] == 'backspace':
        inputText = inputText[:-1]  # lose the final character
        i = i + 1

    elif theseKeys[i] == 'space':
        inputText += ' '
        i = i + 1

    elif theseKeys[i] in ['lshift', 'rshift']:
        shift_flag = True
        i = i + 1

    else:
        if len(theseKeys[i]) == 1:
            # we only have 1 char so should be a normal key, 
            # otherwise it might be 'ctrl' or similar so ignore it
            if shift_flag:
                inputText += chr( ord(theseKeys[i]) - ord(' '))
                shift_flag = False
            else:
                inputText += theseKeys[i]
        i = i + 1

Now I need to know where I should put this:

if theseKeys[i] in key_table.keys(): # only if an equivalent has been defined
 inputText += key_table[theseKeys[i]]
 else:
 inputText += theseKeys[i]
 i = i + 1

or if I should put something else. Wherever I’ve been trying it before, it didn’t work, because of IndexError

For a start, perhaps consider liberally sprinting a few print(i, theseKeys[i]) statements around so you can see where any problems arise.

I suspect you should probably try and integrate that code into the last section of your own code rather than have it separate.

Also note that the trick you are using to get upper case letters (subtracting 32 from their ASCII code) is a very 20th century approach that may very well only work for English ASCII letters. You would probably be better off using a Python function like theseKeys[i].upper() to get an upper case value in a more robust way (having said that, I’m not sure exactly how it will handle Cyrillic characters).

Try something like this but am just dashing this off so no guarantees:

if len(theseKeys[i]) == 1:
    # we only have 1 char so should be a normal key, 
    # otherwise it might be 'ctrl' or similar so ignore it
    if theseKeys[i] in key_table.keys(): # only if an equivalent has been defined

        if shift_flag:
            inputText += key_table[theseKeys[i]].upper()
            shift_flag = False
        else:
            inputText += key_table[theseKeys[i]]

     i = i + 1 # not sure if this is at the right indent level
1 Like

Thank you so much!
Unfortunately, there is an error again:

if theseKeys[i] in key_table.keys():
  ^
IndentationError: expected an indentated block

So I think I’ll have to write conditions for each letter, instead of using libraries, because the problem is probably is that I’m not so familiar with Python.

Psychopy should be able to store Cyrillic letters fine. I haven’t had a lot of time, but I’m hoping to mock up an example for text entry that would allow for different characters, hopefully I can get to it later today and you could easily use it or adapt it.

And that Indentation error is the same one we talked about before, so yes, it does look like you’ll have to brush up on your python :slight_smile:

2 Likes

Well, I ended up making that example, because I had been wanting to do a builder typing demo for a while. Hopefully this doesn’t cause you more trouble since it’s a different approach than the example you’re following, so take it or leave it.

Here’s a simple example showing that you can indeed enter and save Russian text in psychopy (with your example of typing “d” and getting “ф”). It doesn’t do upper case right now, only lower case (it’s not doing anything meaningful with reaction times either). It lets you enter text, and hit enter to save it, 5 times.

typingDemo-russian.psyexp (10.0 KB)

If you wanted to change the keys it accepts, you go to the code component in setupExp. “entryChars” is a list of all of the keynames you want to accept, and the name of the key is what will be displayed (if the keyname is “space”, the participant will see “space”, so don’t put things like “space” in there). “exceptionMap” is a dictionary like Michael showed you: the dictionary key is the keyname, and the value is what you want to display:

exceptionMap = {"space": u" ",
            u"d": u"ф",
}

Here is another, expanded example that will let you change the keyboard at the beginning (for different computers are generating different keynames), has feedback, and saves correct or incorrect responses. I would save it in a different folder from the first example, so you don’t mix up your data.

conditions.xlsx (4.7 KB)
typingDemo.psyexp (15.1 KB)

1 Like

Thank you very much! It seems to fit my experiment, but I need each question to be taken from my list of questins, but now it says that name “Qst” is not defined, thought it works with another scripts.

You’re making it difficult for us to help you. You of course may have to modify the code or column names to get things to work.