I'm creating an experiment using the PsychoPy coder and am not sure how to implement multiple mouse clicks. In the experiment, there are multiple targets and distractors and during a response period, individuals are to select the targets. However, I currently have it where if you click on one of the targets, you get a correct message, otherwise you get an incorrect message. I also have a function that will wait for a mouse click to find the reaction time and will give the response after the mouse click. How do I add multiple mouse clicks for multiple targets?
def waitForMouse(mouse):
mouse.clickReset()
buttons = mouse.getPressed()
while buttons[0] == False: #wait for mouse click
buttons, times = mouse.getPressed(getTime=True) #get reaction time when mouse clicked
return times[0]
if clock.getTime() >= stimDuration: #start of response period
ResponsePrompt.draw() #indicate to participant to select targets
win.flip()
rt = waitForMouse(myMouse)
if myMouse.isPressedIn(target[0]) or myMouse.isPressedIn(target[1]):
CorrectResp.draw() #selected one of the correct targets
win.flip()
core.wait(2) #allow them to read it
else:
IncorrectResp.draw() #answered incorrectly
win.flip()
core.wait(2)
Presumably you have some way of knowing that the participant is "done." You could just do a while loop until exit condition was met. You would just cycle through your mouse function collecting data and appending it to some list that you will later save until the exit condition is met. The basic pseudo-code approach would be something like:
while 1:
catchData = getMouseClickStuff()
<append catchData to whatever list it should be stored to>
if <endConditionMet>:
break
Related
I need to modify a script in psychopy. The thing I need is the subject to press and hold a buttom in the keyboard, but I'd like to have two responses: one when he/her presses it (and the windows with text has to change), and the second when he/her releases it (and the windows with text has to change again).
I am using event.getKeys function of psychopy, and then I'm using keyboard library.
after inizializing the window screen and the text and importing psychopy and the functions I need and keyboard library as key.
intro.draw()
win.flip() # reset the clock to record a response time and clear events
event.clearEvents('all')
event.globalKeys.clear() #to avoid problems with the keys you pressed before
intro_loop = True
while intro_loop:
intro_keys = kb.getKeys(["space"], waitRelease=True)
if key.is_pressed('space'):
intro.text = 'Hi, please follow these instructions :) '
intro.draw()
win.flip() # reset the clock to record a response time and clear events
if len(intro_keys):
win.close()
intro_loop = False
I did the same in another script (just to try) but instead of having a window text screen I printed two different things, and it worked. in this script, instead, it completely ignores the function "key.is_pressed".
do you have any ideas?
I want to stop the automatic scroll down when user scroll up by mouse. I have made a function that scroll's down the webpage automatically after every 2 second but I want to stop that automatic scroll when user scroll up by mouse
My code:
from selenium import webdriver
import time
driver=webdriver.Chrome()
driver.get("https://YouTube.com")
driver. maximize_window()
a=input('press y if you want to scroll down')
if a=='y':
while(True) :
driver. execute_script("window.scrollBy(0, 150) ", "")
time.sleep(2)
else:
Print(" Ok")
One of the ways in which you can solve this is using the window.pageYOffset property.
From the Docs
The read-only Window property pageYOffset is an alias for scrollY; as such, it returns the number of pixels the document is currently scrolled along the vertical axis (that is, up or down) with a value of 0.0, indicating that the top edge of the Document is currently aligned with the top edge of the window's content area.
So what you will have to do is each time you scroll in the loop keep a count of the increase in y and for the condition of your loop, you should check that the pageYOffset == YScrolled. If it equals there's no user input, otherwise there is.
There is a good example here
In making my chess game function for moving pieces, I've created a system that should:
Look for a click
See if a piece was clicked on
Determine what piece was clicked on
Click on a square to move to
Move said piece to said square
I've written the follow code for this:
if event.type == pygame.MOUSEBUTTONDOWN and moving == False:
mousepos = pygame.mouse.get_pos()
roundedmouse1 = rounddown80(mousepos[0]) #function to found out what square was clicked
roundedmouse2 = rounddown80(mousepos[1]) #function to found out what square was clicked
mousecoords = [roundedmouse1,roundedmouse2]
for key,value in piecepositionsdict.items():
if int(value[0]) == int(mousecoords[0]) and int(value[1]) == int(mousecoords[1]):
x = coordstosquaredict[str(mousecoords)]
print("You have clicked",whatpiece(x),"on square",x)
print("Click a square to move the piece to:")
moving = True
time.sleep(0.5)
#this should be where the program stops until it gets another click
if event.type == pygame.MOUSEBUTTONDOWN and moving == True:
mousepos2 = pygame.mouse.get_pos()
roundedmouse21 = rounddown80(mousepos2[0])
roundedmouse22 = rounddown80(mousepos2[1])
mousecoords2 = [roundedmouse21, roundedmouse22]
print(mousecoords2)
print(piecepositionsdict[whatpiece(x)+"pos"])
piecepositionsdict[whatpiece(x)+"pos"] = mousecoords2
print(piecepositionsdict[whatpiece(x) + "pos"])
However, the program goes right past the second click check, as shown by how it prints out mousecoords 2 etc. when I have only clicked once.
What have I done wrong to cause this error?
Games are event driven applications. In event driven application you have a main loop checking for all events, and code executed when an event is detected. The starting point of your logic is always the event.
In your case the event is the clicking of the button. You have to check for the click only once in your code (in the main loop) and then determine the action the code has to do. If different actions may be triggered by the same event, you need some additional logic or flags to determine which action should be executed.
In your case you have an event (mouse click) and two possible actions, check what pieces has been clicked, or move the piece.
So the code should be designed like this:
def check_and_grab(position):
# code here
def move_piece(position):
# code here
piece_grabbed = None
while True:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTODOWN:
if piece_grabbed is None:
check_and_grab(event.pos)
else:
move_piece(event.pos)
piece_grabbed is a variable storing the piece grabbed: if is None, no piece has been grabbed.
check_and_grab(position) should check if there is a piece at the clicked position and, if so, set piece_grabbed to that piece. It implements your points 2 and 3.
move_piece(position) should move the grabbed piece at the new position and after that, set again grabbed_piece = None. It implements your point 5.
Your code will run in a single frame and the code will only register one click during that frame. You need to have a function thats gets called everytime you click on the screen.
See my sort of example bellow:
#Holder for the piece you have selected
currentPiece = piece
##Mouse click event/function##
if currentPiece == None:
getPiece()
else:
movePiece()
##Get piece function##
def getPiece():
#Your function here which sets
#currentPiece to what you selected.
##Move function##
def movePiece():
#Moves the currentPieece to the selected spot
In my experiment, I have 10 trials, and at each trial, the participant has to press a key ("space") asap after seeing a change of colour in the animation. As feedback that confirms the key pressing, I'd like to move to the next trial (move to the next loop iteration) after the key was pressed. I tried to implement the idea in my code with break and continue, but it doesn't work:
for i in range(nTrials):
# Start with fixation cross
fixation.draw()
win.flip()
core.wait(2)
# Play the video for 200 frames
for Nframes in range(200):
optic_flow_movie.draw()
fixation.draw()
win.flip()
# Get Participants responses
keys = psychopy.event.getKeys(keyList=["space"],timeStamped=clock)
if (keys[0][0] == 'space') is True:
break
else:
continue
# Take only the timestamps from the variable key and store it in the variable RTs
RTs = [sublist[1:2] for sublist in keys] # This stores only the timestamps
RTs = [item for sublist in RTs for item in sublist] # This converts from list of lists to a flat list
Many thanks for your help !
It's not entirely clear what the structure of your trial is, but if you want to monitor responses during the animation, then the call to event.getKeys() needs to be embedded within the drawing loop (i.e. within for Nframes in range(200):). That way, you are checking for a keypress on every screen refresh, so the animation can be halted in realtime.
At the moment, the code shows the entire animation and only then checks the keyboard (but just once per trial). Regardless of what happens there, the next trial will begin, as that is the last code in the main trial loop (i.e. for i in range(nTrials):.
Lastly, the event module is deprecated for keyboard responses. You should really shift to the newer Keyboard class for much better performance:
https://www.psychopy.org/api/hardware/keyboard.html
https://discourse.psychopy.org/t/3-ways-to-get-keyboard-input-which-is-best/11184/3
i'm currently developping a program that runs on a robot. The program needs to add positions to a list but you have to push a button to add a new position. This has to be inside a while loop. But when i press the button the function repeats itself multiple times instead of just 1. Here is the part of code:
while not self.done():
if self._io_left_lower.state:
self._gripper_left.open()
elif self._io_left_upper.state:
self._gripper_left.close()
if self._io_right_lower.state:
self._gripper_right.open()
elif self._io_right_upper.state:
self._gripper_right.close()
if self._io_left_nav.button0:
print("repeats")
#self._mapping.append([self._limb_left.joint_angles(), self._gripper_left.position()])
if self._io_right_nav.button0:
self._mapping.append([self._limb_right.joint_angles(), self._gripper_right.position()])
if self._io_left_nav.button1:
self.stop()
As you can see when the self._io_left_nav.button0 is pressed it will now just print 'repeats' several times but it has to to be printed just onces. same for the self._io_right_nav.button0.
If button0 is a physical button and your loop is polling the button state then it is normal that many iterations run in the time your button is being pressed. You have several options to solve this situation, two of them are:
Do not use a loop check the button but hardware interruptions used to keep an updated representation of your state.
If you still want to use your loop, you should detect button state changes instead checking its current state at each iteration. That may require your program to implement a noise filter.
A very simple way to implement the second option is to have a button state variable with a timestamp associated: At each loop iteration, if the difference between the current time and the timestamp is big enought then you should check if the current state is the same than the one stored in the variable. If not then you have detected a change. In any case, at this point you should update your state-timestamp variable.
This is an example:
from time import time
prevState = (False,time())
while not self.done():
current = time()
if self._io_left_nav.button0 and (current-prevState[1])*1000>2: #For example, 2 ms
if self._io_left_nav.button0 != prevState[0]:
print("repeats")
prevState = (self._io_left_nav.button0,time())
I presume that's some kind of flag, that the button was pressed.
If you don't clear the state, the condition in the if statement will evaluate true. Again, and again....