Psychopy事件响应

Psychopy提供了很多IO交互方式,当然,最根本的还是键盘和鼠标。本节介绍Psychopy鼠标和键盘的编程技巧。

全局按键响应

编写刺激界面免不了要反复调试,要看看字体颜色对不对、图形大小合不合适,一旦发现刺激界面需要改进就得退出程序修改源代码。

如果采用普通的按键检测方式,则需要在一个循环体内检查按键状态,这显然有可能造成不可知的错误(比如在检测按键前进入一个死循环函数,程序永远无法退出啦),这个时候全局按键响应就很有用了。

Psychopy用psychopy.event.globalkeys来设置全局按键,官方文档里没有如何使用全局按键的说明,但在coder的Demo里有演示global_event_keys.py。

global_event.keys.py程序注册了三个按键,按键“b”调用python的setattr函数,设置rect对象的填充颜色为蓝色,按键“ctrl”+“r”调用python的setattr函数,设置rect对象的填充颜色为红色。按键“q”调用core.quit方法终止程序退出。

# -*- coding: utf-8 -*-

from psychopy import core, event, visual, monitors


if __name__=='__main__':
mon = monitors.Monitor(
name='my_monitor',
width=53.704, # 显示器宽度,单位cm
distance=45, # 被试距显示器距离,单位cm
gamma=None, # gamma值
verbose=False) # 是否输出详细信息
mon.setSizePix((1920, 1080)) # 设置显示器分辨率
mon.save() # 保存显示器信息

win = visual.Window(monitor=mon, size=(800, 600), fullscr=False,
screen=0, winType='pyglet', units='norm', allowGUI=False)
rect = visual.Rect(win, fillColor='blue', pos=(0, -0.2))
text = visual.TextStim(
win,
pos=(0, 0.5),
text=('Press\n\n'
'B for blue rectangle,\n'
'CTRL + R for red rectangle,\n'
'Q or ESC to quit.'))

# Add an event key.
event.globalKeys.add(key='b', func=setattr,
func_args=(rect, 'fillColor', 'blue'),
name='blue rect')

# Add an event key with a "modifier" (CTRL).
event.globalKeys.add(key='r', modifiers=['ctrl'], func=setattr,
func_args=(rect, 'fillColor', 'red'),
name='red rect')

# Add multiple shutdown keys "at once".
for key in ['q', 'escape']:
event.globalKeys.add(key, func=core.quit)

# Print all currently defined global event keys.
print(event.globalKeys)
print(repr(event.globalKeys))

while True:
text.draw()
rect.draw()
win.flip()

以下是event.globalkeys.add()方法的参数介绍
event.globalkeys.add(key, func, func_args=(), func_kwargs=None, modifiers=(), name=None)

parameterstypedescription
keystring按键字符串
funcfunction按键时执行的函数
func_argsiterable函数的args参数
func_kwargsdict函数的kwargs参数
modifiersiterable组合按键字符串列表,例如’shift’,‘ctrl’,‘alt’,‘capslock’,'scrollock’等
namestring按键事件的名称

此外还有event.globalkeys.remove()方法以移除全局按键
event.globalkeys.remove(key, modifiers=())

parameterstypedescription
keystring按键字符串
modifiersiterable组合按键字符串列表,例如’shift’,‘ctrl’,‘alt’,‘capslock’,'scrollock’等

等待按键和检测按键

除了全局按键响应,Psychopy还提供了等待按键响应和检测按键响应两种方式。

以下为等待按键函数event.waitKeys()的演示程序,按’esc’或五次其他按键退出程序。

# -*- coding: utf-8 -*-

from psychopy import core, event, visual, monitors


if __name__=='__main__':
mon = monitors.Monitor(
name='my_monitor',
width=53.704, # 显示器宽度,单位cm
distance=45, # 被试距显示器距离,单位cm
gamma=None, # gamma值
verbose=False) # 是否输出详细信息
mon.setSizePix((1920, 1080)) # 设置显示器分辨率
mon.save() # 保存显示器信息

win = visual.Window(monitor=mon, size=(800, 600), fullscr=False,
screen=0, winType='pyglet', units='norm', allowGUI=False)
msg = visual.TextStim(win, text='press a key\n < esc > to quit')
msg.draw()
win.flip()

k = ['']
count = 0
while k[0] not in ['escape', 'esc'] and count < 5:
k = event.waitKeys()
print(k)
count += 1

win.close()
core.quit()

event.waitKeys()阻塞函数进程直到被试按键,以下是event.waitKeys()方法的参数介绍
event.waitKeys(maxWait=inf, keyList=None, modifiers=False, timeStamped=False, clearEvents=True)

parameterstypedescription
maxWaitnumeric value最大等待时间,默认为inf
keyListiterable指定函数检测的按键名称,函数仅在按指定键时返回
modifiersbool如果True,返回(keyname, modifiers)的tuple
timeStampedbool如果True,返回(keyname, time)
clearEventsbool如果True,在检测新的按键前清理event buffer
returntypedescription
keysiterable按键列表;超时返回None

等待按键会阻塞进程,Psychopy还提供了另一种非阻塞检测方式event.getKeys()

以下代码如下不断检测按键并输出,直到按’escape’键退出程序。

# -*- coding: utf-8 -*-

from psychopy import core, event, visual, monitors


if __name__=='__main__':
mon = monitors.Monitor(
name='my_monitor',
width=53.704, # 显示器宽度,单位cm
distance=45, # 被试距显示器距离,单位cm
gamma=None, # gamma值
verbose=False) # 是否输出详细信息
mon.setSizePix((1920, 1080)) # 设置显示器分辨率
mon.save() # 保存显示器信息

win = visual.Window(monitor=mon, size=(800, 600), fullscr=False,
screen=0, winType='pyglet', units='norm', allowGUI=False)
msg = visual.TextStim(win, text='press a key\n < esc > to quit')
msg.draw()
win.flip()

count = 0
while True:
k = event.getKeys()
if k:
if 'escape' in k:
break
print(k)

win.close()
core.quit()

以下是event.getKeys()方法的参数介绍
event.getKeys(keyList=None, modifiers=False, timeStamped=False)

parameterstypedescription
keyListiterable指定函数检测的按键名称,函数仅在按指定键时返回
modifiersbool如果True,返回(keyname, modifiers)的tuple
timeStampedbool如果True,返回(keyname, time)
returntypedescription
keysiterable按键列表;超时返回None

鼠标事件

Psychopy提供event.Mouse类来处理鼠标相关的事件,官方文档对此有详细的介绍。以下的代码显示了一个含有矩形的窗,在矩形内部单击左右键可以改变颜色,而按中央滚轮键则退出程序。

# -*- coding: utf-8 -*-

from psychopy import core, event, visual, monitors


if __name__=='__main__':
mon = monitors.Monitor(
name='my_monitor',
width=53.704, # 显示器宽度,单位cm
distance=45, # 被试距显示器距离,单位cm
gamma=None, # gamma值
verbose=False) # 是否输出详细信息
mon.setSizePix((1920, 1080)) # 设置显示器分辨率
mon.save() # 保存显示器信息

win = visual.Window(monitor=mon, size=(800, 600), fullscr=False,
screen=0, winType='pyglet', units='norm', allowGUI=True)
rect = visual.Rect(win, fillColor='blue', pos=(0, 0))

# 创建Mouse类
mouse = event.Mouse(visible=True, newPos=(0, 0), win=win)
while True:
# 重置单击事件状态
mouse.clickReset()

# 检测左键是否在矩形内单击
if mouse.isPressedIn(rect, buttons=[0]):
rect.fillColor = 'red'

# 检测右键是否在矩形内单击
if mouse.isPressedIn(rect, buttons=[2]):
rect.fillColor = 'blue'

# 检测是否单击滚轮键
# button1: left click
# button2: middle click
# button3: right click
button1, button2, button3 = mouse.getPressed(getTime=False)
if button2:
break

rect.draw()
win.flip()

core.quit()