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?
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.
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.
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.
@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.
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.
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
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
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)
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.