Cursor jitter on mouse movement only

I’ve narrowed down the bug somewhat. The problem is that mouse.setPos(new_coordinate) does not result in mouse.getPos() to return exactly new_coordinate but rather something quite close. Therefore, mouse.getRel() detects this as a movement. The problem is in GL, so it’s out of reach for PsychoPy.

Solution #1

The solution is to only call mouse.setPos when the system cursor reaches the screen edge instead of doing it every frame. In my case, the code is

if any(abs(mouse.getPos()*1.1) >= 1):  # if system mouse is outside screen border
    mouse.setPos(cursor.pos)  # to allow for continued movement even though a regular cursor would have exited the monitor edges
    core.wait(0.008)  # this solves a weird mouse problem, where it "jumps" randomly on mouse.setPos.
    mouse.lastPos = cursor.pos  # Needed to not count the above move as an acceleration.            

The if-statement is a bit more convoluted if you work in different window units. For instance, I do it in degrees visual angle, so it’s:

if any(abs(mouse.getPos()*1.1) >= pix2deg(np.array(MON_SIZE)/2, my_monitor)):  # if system mouse is outside screen border

… where MON_SIZE=[1440, 2560] on my system (monitor size in pixels) and my_monitor is an psychopy.monitors.Monitor object. pix2deg is psychopy.misc.monitortools.pix2deg.

Solution #2

A different is to specify a minimum movement distance to seperate physical mouse movements from system-noise-movement. In my original example, outcomment all code and then substitute

if np.any(move):

with

if np.any(np.abs(move) >= 0.005):  

… or whatever criterion you find appropriate. For units=‘pix’, 1 is a good threshold. FWIW it seems like the signal-to-noise ratio seems higher for units='pix' than for units='norm', i.e. the threshold does better in distinguishing physical mouse movement from noise. I haven’t tested it much.

Other event.Mouse bugs

Thanks a bunch @rob.stone and @porcu.emanuele for your code examples. This made the debugging a lot easier. In debugging this, I discovered other bugs in the event.Mouse class. I will submit fixes to GitHub. Until then, here they are for completeness:

  • Mouse.setPos(x) where x is not the current mouse position does not result in mouse.getPos() in returning x but something rather close. This is a deterministic behavior (it’s repeatable) but with no obvious mechanism. For example, the error seems to be somewhat proportional to the amount of mouse displacement, but not exactly. There also seems to be a minimum movement below which there is no inaccuracy.
  • mouse.mouseMoved() will only run if mouse.lastPos is set and that is only set if mouse.getPos() has been called. This should not be necessary.
  • mouse.mouseMoved(reset=False) still resets the position so that a subsequent mouse.getRel() will return [0,0] even on movement.
  • Perhaps not a bug, but surprising behavior to me: mouse.setPos(x) counts as movement, i.e. detected by mouse.getRel() and mouse.mouseMoved(). If this is intended, there should be an argument like mouse.setPos(x, as_movement=True)
2 Likes