Search code examples
pythonpsychopy

Python/Psychopy: Logging mouse click locations


Using the code below, I'm trying to open a window for 10 seconds, have the user click anywhere on the screen as many times as they wish, and I want to log the mouse click locations. Every time the user clicks within the window (i.e. myMouse.getPressed) occurs, I'm appending the click location to a list (mouse_click_locations[]). However, the list is being appended with the same click location many times, on every frame. I want to append the click location to the list once, and no more until another click is initiated. I thought that adding 'myMouse.clickReset()' at the end of each frame would do this, but it doesn't make a difference.

After 10 seconds, I want the list to be populated with one location (x,y coord) for each mouse click initiated.

from psychopy import visual, core, gui, event, sound

win = visual.Window([800,600],color=(1,1,1), colorSpace='rgb', 
rgb=None, allowGUI=True, monitor='testMonitor', 
units='deg', fullscr=False)

myMouse = event.Mouse(visible=True,win=win)

refresh_rate = 60.0
default_time = 10

time_window = default_time * refresh_rate
time_window = int(time_window)

running = 1
while running:

    mouse_click_locations = []

    for frame in range(time_window):

        mouse_loc = myMouse.getPos()
        mouse_click = myMouse.getPressed()

        if mouse_click:
            mouse_click_locations.append(mouse_loc)

        win.flip()
        myMouse.clickReset()

    running = 0

win.close()

print mouse_click_locations

Could someone help me achieve this? am I using myMouse.clickReset() incorrectly?

Cheers, Jon


Solution

  • This happens because the script checks the mouse state for every iteration in your frame-loop; i.e. 60 times a second. As you say, you only want to get a single event for each mouse-down. Here's one solution where you simply halt the script until all buttons are released. Also note the use of any to explicitly check all buttons.

    # Record mouse position if a key is pressed
    if any(myMouse.getPressed())  # Any button pressed, no matter which
        mouse_click_locations.append(myMouse.getPos())
    
    # Wait until all buttons are released
    while any(myMouse.getPressed()):
        pass
    

    No need to use mouse.clickReset. As a small comment, you do not update visual stuff on the screen, so you do not need to include win.flip in the loop. Because it waits for the next monitor update, it effectively rounds off reaction times (if you need these) to nearest 1/60 second interval. This, and relying a bit on defaults, would also simplify the script a great deal:

    default_time = 10
    
    from psychopy import visual, core, event    
    win = visual.Window(color='white', monitor='testMonitor', units='deg')
    myMouse = event.Mouse(visible=True, win=win)
    clock = core.ClocK()
    
    # Collect unique click events before time runs out
    mouse_click_locations = []
    while clock.getTime() < default_time:
        # Record mouse position if a key is pressed
        if any(myMouse.getPressed())  # Any button pressed, no matter which
            mouse_click_locations.append(myMouse.getPos())
    
        # Wait until all buttons are released
        while any(myMouse.getPressed()):
            pass
    
    print mouse_click_locations