Sunday, August 3, 2008

Free text entry

This function provides a way for participants to type a response freely (with spaces, backspace etc.), returning the text that they typed.

See also: the discussion on SourceForge about this very topic.

Update: I just noticed another post on the SourceForge forum that looks like it deals with freetext typing, but I haven't tried Aaron's solution.


#!/usr/bin/python

from pyepl.locals import *
from pyepl import timing, display, keyboard, exputils
import string


##############################
def textBox(clk=None,
keys=None,
time_limit=None,
disptxt='',
wordHeight=None,
showProportional=(.5,.5)):
"""
Allows freeform text entry, including BACKSPACE, until
RETURN or ENTER are pressed. Allows you to define your
own set of allowed keys and a time limit.

CLK = a PresentationClock

KEYS = a list of keys (as strings) that will
register. All other keys will be ignored. Defaults to
just the lowercase keys, plus RETURN/ENTER, BACKSPACE
and SPACE. To define your own, follow this example:

keys = list(string.lowercase) + ['RETURN','ENTER','BACKSPACE','SPACE']

N.B. Make sure to include at least RETURN or ENTER,
since textBox is hardcoded to wait for one of those
keys to end text entry.

TIME_LIMIT

DISPTXT = this will be displayed until the user types
the first key, after which it will be replaced with
whatever they type

[Based on the pyepl/convenience.py/mathDistract function.]

todo:

- it should log every keypress with a timestamp, in case
you want to do some kind of crazy RT analysis. For
now, i think it's probably somewhere buried in the
KeyTrack.
"""

# get the tracks
v = display.VideoTrack.lastInstance()
k = keyboard.KeyTrack.lastInstance()

if clk is None: clk = exputils.PresentationClock()

# we only need to calculate the END_TIME (i.e. the
# time we're going to stop) if we have a time limit
if time_limit: end_time = timing.now() + time_limit

if keys is None:
keys = list(string.lowercase) + ['RETURN','ENTER','BACKSPACE','SPACE']

ans_but = k.keyChooser(*keys)

# show the DISPTXT that will be replaced after the first keypress
# rt = v.showCentered(Text(disptxt,size=wordHeight))
rt = v.showProportional(Text(disptxt,size=wordHeight),
showProportional[0],showProportional[1])
v.updateScreen(clk)

# wait for keypress
kret,timestamp = ans_but.waitWithTime(maxDuration=time_limit, clock=clk)
# throw away the starting text, and get ready to display
# whatever the user typed
disptxt = ''

while kret and (kret.name != "RETURN" and kret.name != "ENTER"):
# process the response
if kret.name == 'BACKSPACE':
# remove last char
if len(disptxt) > 0:
disptxt = disptxt[:-1]
elif kret.name == 'RETURN' or kret.name == 'ENTER':
pass
elif kret.name == 'SPACE':
disptxt = disptxt + ' '
else:
# just append it
disptxt = disptxt + kret.name

# update the text - we need to do it in two
# steps rather than with replace, because
# replace doesn't re-center it
# rt = v.replace(rt,Text(disptxt))
v.unshow(rt)
rt = v.showProportional(Text(disptxt,size=wordHeight),
showProportional[0],showProportional[1])
v.updateScreen(clk)

# wait for another response
if time_limit: time_limit = end_time - timing.now()

kret,timestamp = ans_but.waitWithTime(maxDuration=time_limit,clock=clk)

# print 'You typed: ' + disptxt
return disptxt

No comments: