Potential Problem with Mac OSX for Mouse Detection

So, I have been in discussion with a couple others trying to perfect a code for my mouse movements on another forum topic. However, it has come to my attention that the code is simple and affective, but does not seem to work on my current device as it should.

As the topic notes, I am using a Macbook for my development process. When I sent the code to my desktop pc, it worked as expected. Additionally, other people on the forums also said that this code worked as expected. I will post the code below as well as the issue.

Here is the issue: When running this code, “XDiff” determines the displacement of X at every frame. However, on my Mac, even though I constantly move my mouse, it only recognizes that the mouse is moving about once every 15 frames. Otherwise, it states that the mouse is at position 0,0 at the center of the screen which is not the case, or rather should not be the case. The code never signifies that it loses the pass. Additionally, if I make an extra stipulation that I have to hold Right-Click to turn, it will still print the same results; therefore, the mouse is certainly being detected this entire time.

CODE

from direct.showbase.ShowBase import ShowBase
from panda3d.core import *
class Game(ShowBase):
def init(self):
ShowBase.init(self)
self.accept(“escape”, base.userExit)
self.disableMouse()
self.setFrameRateMeter(True)

    self.environment = loader.loadModel("Environment/PracticeMap2")
    self.environment.reparentTo(render)
    self.environment.setPos(0,0,-2)
    
    self.dummyNode = render.attachNewNode("dummyNode")
    self.dummyNode.setPos(-2,-5,2)
    self.cameraNode = base.camera.reparentTo(self.dummyNode)
    self.camera.setPos(.5, -4, 5)
    self.dummyNode.setP(30)
    self.camera.setP(-35)

    self.MouseSensitivity = 10
    X = int(base.win.getXSize()/2)
    Y = int(base.win.getYSize()/2)
    base.win.movePointer(0, X, Y)
    self.mouseCenter = [X,Y]

    self.task_mgr.add(self.Look, "Look")

def Look(self,task):

    if base.mouseWatcherNode.hasMouse():
        XDiff = base.mouseWatcherNode.getMouseX()
        base.win.movePointer(0, self.mouseCenter[0], self.mouseCenter[1])
    else:
        XDiff = 0
    print(XDiff)
    self.dummyNode.setH(self.dummyNode.getH() + 100*XDiff*-1) 

    

    return task.cont

app = Game()
app.run()

Example of return for printing XDiff (Note Even while restricting FPS to 60 in config)

0.1614062786102295
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0

I think the problem is that when you reset the cursor on macOS, the operating system throws away the “subpixel” information of the mouse position. If the application is running so fast that every frame it detects that the mouse has only moved by 0.4 of a pixel, this movement will be lost when the mouse pointer is reset back to 0.

On Windows, however, this is not a problem because the operating system doesn’t throw away this information. If the mouse X is at 3.4 and we reset it to 0, it actually resets it to 0.4.

The best way to deal with this is to use the “relative” mouse mode. This will make the operating system return only the deltas of the mouse movement to Panda3D, so this issue will not occur. At the same time, the reported X Y will not be constrained to the window boundaries, so you will not need to reset the cursor.

The relative mode does not work on Windows, however, so you need to still reset the pointer as fallback. It does work on Linux.

2 Likes

Wow, thank you so much! This is extremely helpful. I certainly would not have ever realized this haha. I am not quite positive on the process of using “relative” mouse mode; however, I am sure I can find more detail on this in the manual and other forum posts

EDIT:
Wow so me just setting this in my initialization fixes everything.

To set relative mode and hide the cursor:

props = WindowProperties()
props.setCursorHidden(True)
props.setMouseMode(WindowProperties.M_relative)
self.base.win.requestProperties(props

Ive been trying to fix this for over a week now and all I had to do was set it to a relative mouse mode. Im so happy but also fuming lol

Although again, bear in mind that this will presumably not work under Windows, as rdb mentioned above. Fallback code, using what you previously had, might be called for if you intend to run your application under Windows at some point.

(If you don’t intend to run your application under Windows, of course, then all should be well!)

Hm, interesting. So my code is technically still “resetting” the pointer just as the initial code was doing at the beginning. But would I also have to de-initialize the relative mode as well? So basically, detect whether the system is Windows/Mac/Linux and then determine whether to initialize the relative mouse mode or not?

Well, not de-initialise it, but simply not activate it in the first place, if I’m not much mistaken. In addition, I think that that resetting the pointer is not required at all in relative mode, so you could omit that when relative mode is used.

1 Like

Ah ok, I see! That shouldnt be too difficult. Thanks for the tip!

1 Like