Experimenting a bit after reading your comments, I found out that the following program puts the mouse correctly at the center of the screen
from psychopy import core,visual,event
FULLSCREEN = True
win = visual.Window([800,600],monitor="monitor",rgb = [0,0,0],winType='pyglet',waitBlanking=True,units='pix', allowGUI=False,fullscr=FULLSCREEN)
myMouse = event.Mouse(visible=True,newPos=[0,0],win=win)
print(win.size)
if win.useRetina:
#myMouse.setPos([0-800*0.5,0-600*0.5])
myMouse.setPos([0-win.size[0]*0.25,0-win.size[1]*0.25])
msg = visual.TextStim(win, text='')
msg.setAutoDraw(True)
while True:
pos = myMouse.getPos()
msg.text = str(pos)
win.flip()
if 'escape' in event.getKeys():
core.quit()
This solves this mouse location problem but I’m encountering other problems which seems to be linked to the mouse location but that cannot be fixed as easily. Notably, the program below is based on a program for which I started noticing this problem. It used to work well on Psychopy2 1.85.4.
from psychopy import visual,event,core
cl = core.Clock()
#RESPONSE PANEL PARAMETERS
serif = ['Arial']
scaling = 0.95 #To increase/decrease all the elements in the response panel
responsePanelTextSizeButton = (40/1.3)*scaling #Control the size of the text inside the button of the response panel
#Control the line in the lickert scale
lineScale = 1.2 #Control the size of the line. Allows the button to scale immediately with it
posLineX = 0*scaling #X position of the center of the line
posLineY = -0*scaling #Y position of the center of the line
lineWidth = 590*scaling*lineScale #Width of the line
lineHeight = 2.5*scaling #Heigth of the line
#General appearance for the appearance of the buttons and the accompanying lables
buttonTextSize = 17.0*scaling #13 Determines the size of the font
borderColor = "Black" #Determines the color of the border of the buttons
inactiveColor = "White" #Determines the color of the buttons when inactive
activeColor = "Black" #Determines the color of the buttons when active
betweenButtons = 56*scaling*lineScale #Distance between buttons
buttonRadius = 22*scaling*lineScale #radius of the buttons
buttonOutWidth = 2 #Thickness of the border line of the buttons
buttonX = -280*scaling*lineScale #X position of the left most button
textY = 1.2*(-60/1.3)*scaling #Y position of the first level of text
#Control the location of the numbers inside the buttons. Watch out! Number 10 requires special adjustment
buttonNumberPosAdjX = 2*(-12/1.3)*scaling
buttonNumberPosAdjY = (-25/1.3)*scaling
#MOUSE PARAMETERS
xMouse = 0 #xlocation of the mouse when the response panel is shown.
yMouse = -200 #ylocation of the mouse when the response panel is shown.
clickDuration = 0.15 #Control the duration of the feedback given when participants click on the response panel (sec)
def waitForMouseClick(myMouse):
waiting = True
#Waiting for mouse to be pressed
while (waiting):
buffer = checkKeyboard()
if buffer == 'escape':
sys.exit()
buttons = myMouse.getPressed()
if (buttons[0] == 1):
waiting = False
waiting = True
#Waiting for mouse to be released
while (waiting):
buttons = myMouse.getPressed()
if sum(buttons) == 0:
waiting = False
return
def checkKeyboard():
for key in event.getKeys():
if key in ['q']:
sys.exit()
else:
event.clearEvents()
def wait(duration):
t = cl.getTime()
while(cl.getTime()-t)<duration:
pass
return
class responsePanel:
def __init__ (self):
self.respLine = visual.GratingStim(win,
units="pix",
tex="None",
mask="None",
texRes=256,
pos=(posLineX,posLineY),
size=[lineWidth,lineHeight],
sf=[0,0],
ori = 0,
name='picFrame',
rgb=(-1,-1,-1))
self.b1 = visual.Circle(win,
units='pix',
radius = buttonRadius,
edges=32,
lineWidth = buttonOutWidth,
fillColor = inactiveColor,
lineColor = borderColor,
pos=(buttonX,posLineY))
self.b2 = visual.Circle(win,
units='pix',
radius = buttonRadius,
edges=32,
lineWidth = buttonOutWidth,
fillColor = inactiveColor,
lineColor = borderColor,
pos=((buttonX+betweenButtons*1),posLineY))
self.b3 = visual.Circle(win,
units='pix',
radius = buttonRadius,
edges=32,
lineWidth = buttonOutWidth,
fillColor = inactiveColor,
lineColor = borderColor,
pos=((buttonX+betweenButtons*2),posLineY))
self.b4 = visual.Circle(win,
units='pix',
radius = buttonRadius,
edges=32,
lineWidth = buttonOutWidth,
fillColor = inactiveColor,
lineColor = borderColor,
pos=((buttonX+betweenButtons*3),posLineY))
self.b5 = visual.Circle(win,
units='pix',
radius = buttonRadius,
edges=32,
lineWidth = buttonOutWidth,
fillColor = inactiveColor,
lineColor = borderColor,
pos=((buttonX+betweenButtons*4),posLineY))
self.b6 = visual.Circle(win,
units='pix',
radius = buttonRadius,
edges=32,
lineWidth = buttonOutWidth,
fillColor = inactiveColor,
lineColor = borderColor,
pos=((buttonX+betweenButtons*5),posLineY))
self.b7 = visual.Circle(win,
units='pix',
radius = buttonRadius,
edges=32,
lineWidth = buttonOutWidth,
fillColor = inactiveColor,
lineColor = borderColor,
pos=((buttonX+betweenButtons*6),posLineY))
self.b8 = visual.Circle(win,
units='pix',
radius = buttonRadius,
edges=32,
lineWidth = buttonOutWidth,
fillColor = inactiveColor,
lineColor = borderColor,
pos=((buttonX+betweenButtons*7),posLineY))
self.b9 = visual.Circle(win,
units='pix',
radius = buttonRadius,
edges=32,
lineWidth = buttonOutWidth,
fillColor = inactiveColor,
lineColor = borderColor,
pos=((buttonX+betweenButtons*8),posLineY))
self.b10 = visual.Circle(win,
units='pix',
radius = buttonRadius,
edges=32,
lineWidth = buttonOutWidth,
fillColor = inactiveColor,
lineColor = borderColor,
pos=((buttonX+betweenButtons*9),posLineY))
self.b11 = visual.Circle(win,
units='pix',
radius = buttonRadius,
edges=32,
lineWidth = buttonOutWidth,
fillColor = inactiveColor,
lineColor = borderColor,
pos=((buttonX+betweenButtons*10),posLineY))
self.b1Number = visual.TextStim(win,
units='pix',height = responsePanelTextSizeButton,
pos=((buttonX+buttonNumberPosAdjX),(posLineY+buttonNumberPosAdjY)), text=" 0",
font=serif,
wrapWidth=700,
alignHoriz = 'left',alignVert='bottom',
color='Black')
self.b2Number = visual.TextStim(win,
units='pix',height = responsePanelTextSizeButton,
pos=(((buttonX+betweenButtons*1)+buttonNumberPosAdjX),(posLineY+buttonNumberPosAdjY)), text="10",
font=serif,
wrapWidth=700,
alignHoriz = 'left',alignVert='bottom',
color='Black')
self.b3Number = visual.TextStim(win,
units='pix',height = responsePanelTextSizeButton,
pos=(((buttonX+betweenButtons*2)+buttonNumberPosAdjX),(posLineY+buttonNumberPosAdjY)), text="20",
font=serif,
wrapWidth=700,
alignHoriz = 'left',alignVert='bottom',
color='Black')
self.b4Number = visual.TextStim(win,
units='pix',height = responsePanelTextSizeButton,
pos=(((buttonX+betweenButtons*3)+buttonNumberPosAdjX),(posLineY+buttonNumberPosAdjY)), text="30",
font=serif,
wrapWidth=700,
alignHoriz = 'left',alignVert='bottom',
color='Black')
self.b5Number = visual.TextStim(win,
units='pix',height = responsePanelTextSizeButton,
pos=(((buttonX+betweenButtons*4)+buttonNumberPosAdjX),(posLineY+buttonNumberPosAdjY)), text="40",
font=serif,
wrapWidth=700,
alignHoriz = 'left',alignVert='bottom',
color='Black')
self.b6Number = visual.TextStim(win,
units='pix',height = responsePanelTextSizeButton,
pos=(((buttonX+betweenButtons*5)+buttonNumberPosAdjX),(posLineY+buttonNumberPosAdjY)), text="50",
font=serif,
wrapWidth=700,
alignHoriz = 'left',alignVert='bottom',
color='Black')
self.b7Number = visual.TextStim(win,
units='pix',height = responsePanelTextSizeButton,
pos=(((buttonX+betweenButtons*6)+buttonNumberPosAdjX),(posLineY+buttonNumberPosAdjY)), text="60",
font=serif,
wrapWidth=700,
alignHoriz = 'left',alignVert='bottom',
color='Black')
self.b8Number = visual.TextStim(win,
units='pix',height = responsePanelTextSizeButton,
pos=(((buttonX+betweenButtons*7)+buttonNumberPosAdjX),(posLineY+buttonNumberPosAdjY)), text="70",
font=serif,
wrapWidth=700,
alignHoriz = 'left',alignVert='bottom',
color='Black')
self.b9Number = visual.TextStim(win,
units='pix',height = responsePanelTextSizeButton,
pos=(((buttonX+betweenButtons*8)+buttonNumberPosAdjX),(posLineY+buttonNumberPosAdjY)), text="80",
font=serif,
wrapWidth=700,
alignHoriz = 'left',alignVert='bottom',
color='Black')
self.b10Number = visual.TextStim(win,
units='pix',height = responsePanelTextSizeButton,
pos=(((buttonX+betweenButtons*9)+buttonNumberPosAdjX),(posLineY+buttonNumberPosAdjY)), text="90",
font=serif,
wrapWidth=700,
alignHoriz = 'left',alignVert='bottom',
color='Black')
self.b11Number = visual.TextStim(win,
units='pix',height = responsePanelTextSizeButton,
pos=(((buttonX+betweenButtons*10)+buttonNumberPosAdjX-((12/1.3)*scaling)),(posLineY+buttonNumberPosAdjY)), text="100",
font=serif,
wrapWidth=700,
alignHoriz = 'left',alignVert='bottom',
color='Black')
def draw(self):
self.respLine.draw()
self.b1.draw()
self.b2.draw()
self.b3.draw()
self.b4.draw()
self.b5.draw()
self.b6.draw()
self.b7.draw()
self.b8.draw()
self.b9.draw()
self.b10.draw()
self.b11.draw()
self.b1Number.draw()
self.b2Number.draw()
self.b3Number.draw()
self.b4Number.draw()
self.b5Number.draw()
self.b6Number.draw()
self.b7Number.draw()
self.b8Number.draw()
self.b9Number.draw()
self.b10Number.draw()
self.b11Number.draw()
def showPanel(self,mouse): #[retentionInterval,firstRecovery,[inst1a,inst1b,inst2]]
self.draw()
mouse.setPos(newPos=[0,0])
mouse.setVisible(1)
win.flip()
resp = self.recordResponse(mouse)
mouse.setVisible(0)
return resp
def recordResponse(self,mouse):
event.clearEvents()
while True:
buffer = waitForMouseClick(mouse)
if self.b1.contains(mouse):
self.activateButton(self.b1)
return 0
elif self.b2.contains(mouse):
self.activateButton(self.b2)
return 10
elif self.b3.contains(mouse):
self.activateButton(self.b3)
return 20
elif self.b4.contains(mouse):
self.activateButton(self.b4)
return 30
elif self.b5.contains(mouse):
self.activateButton(self.b5)
return 40
elif self.b6.contains(mouse):
self.activateButton(self.b6)
return 50
elif self.b7.contains(mouse):
self.activateButton(self.b7)
return 60
elif self.b8.contains(mouse):
self.activateButton(self.b8)
return 70
elif self.b9.contains(mouse):
self.activateButton(self.b9)
return 80
elif self.b10.contains(mouse):
self.activateButton(self.b10)
return 90
elif self.b11.contains(mouse):
self.activateButton(self.b11)
return 100
def activateButton(self,button):
button.setFillColor(activeColor)
self.draw()
win.flip()
wait(clickDuration)
button.setFillColor(inactiveColor)
win.flip()
FULLSCREEN = False
win = visual.Window([1024,768],monitor="monitor",rgb=[0,0,0],winType='pyglet',waitBlanking=True,units='pix', allowGUI=False,fullscr=False)
myMouse = event.Mouse(visible=True,newPos=[0,0],win=win)
testPanel = responsePanel()
while True:
print (testPanel.showPanel(myMouse))
I apologise as the code is a bit long but basically, it creates a a 11-point Lickert scale going from 0 to 10: the participant click on the number to provide his answer.
In Psychopy3, and I think in versions of Psychopy2 released after 1.85.4, the program works strangely: (a) If you click on button 50 (whose location must be 0,0 at the center of the screen), button 50 is activated but (b) if you click on button 40, button 30 is activated; if you click on button 30, button 10 is activated; nothing happens if you click on buttons 20, 10 and 0. Likewise, © if you click on button 60, button 70 is activated; if you click on button 70, button 90 is activated; nothing happens if you click on buttons 80, 90 and 100.
So there seems some kind of non-linear distortion between the actual position of the mouse on the x-axis and the position recorded by psychopy.
The part of the program dealing with the location of the mouse is the following method
def recordResponse(self,mouse):
event.clearEvents()
while True:
buffer = waitForMouseClick(mouse)
if self.b1.contains(mouse):
self.activateButton(self.b1)
return 0
elif self.b2.contains(mouse):
self.activateButton(self.b2)
return 10
elif self.b3.contains(mouse):
self.activateButton(self.b3)
return 20
elif self.b4.contains(mouse):
self.activateButton(self.b4)
return 30
elif self.b5.contains(mouse):
self.activateButton(self.b5)
return 40
elif self.b6.contains(mouse):
self.activateButton(self.b6)
return 50
elif self.b7.contains(mouse):
self.activateButton(self.b7)
return 60
elif self.b8.contains(mouse):
self.activateButton(self.b8)
return 70
elif self.b9.contains(mouse):
self.activateButton(self.b9)
return 80
elif self.b10.contains(mouse):
self.activateButton(self.b10)
return 90
elif self.b11.contains(mouse):
self.activateButton(self.b11)
return 100
It waits for a mouse click and check if that click has taken place in one of the b1 to b11 visual.Circle objects, using the contains(mouse) method build in in the visual.Circle class. I believe the problem is in that contains() method and the way it handles the mouse position with a retina display.