Disabling mouse-events

Is there a means to–temporarily!–disable mouse-events entirely, but with the caveat of not disrupting detection of the mouse-position?

To explain, I’m working on the navigation of my current project’s UI via means other than the mouse. That is, navigation via things like gamepads, keyboard, etc.

Now, for the most part I have a functional system for this, I believe. However, there is a problem: if the mouse is left hovering over a UI element, mouse-events (such as a bound “DGG.ENTER”) seem to still be fired as a result. This then results in some bugs.

I can likely handle at least some of this myself–I can get a callback when entering “non-mouse mode” and unbind events like “DGG.ENTER”.

However, that means doing so for all relevant UI elements. And further, I suspect that it won’t work for the built-in mouse-driven state-changes (things like the standard hover-behaviour of a DirectButton). And further, I don’t want to just disable my UI elements because I still want them to react to the non-mouse navigation as though to a mouse-cursor.

Thus I’m hoping that there’s a “global” way of disabling the effect of the mouse.

However, I do nevertheless want to retain the ability to query the position of the mouse, so that I can detect the player attempting to return to “mouse mode”.

I’ve looked at the MouseWatcher class, but I don’t see any methods that seem likely to disable its events.

I suppose that I could detach the standard mouse-watcher node, but I don’t know how that’s properly done–or what the consequences of detaching and reattaching it might be. Especially given that I have at least one custom mouse-watching present…

So, thoughts?

I came up with the idea of ​​using an additional flag for mouse button handlers. You can do the same for the keyboard

I think you’re on the right track with disabling the MouseWatcher. You can probably do this by calling stash() and unstash() on the node. Or even disable the MouseAndKeyboard node that sits above it in the data graph.

You can also create a MouseWatcherRegion with appropriate SuppressFlags set and have it cover all of the UI that you no longer want responding to mouse events (or create a transparent but active DirectFrame that does the same thing under the hood).

MouseWatcherRegion is the class that the GUI system uses under the hood to watch regions for mouse events, and the suppress flags on it tell the MouseWatcher not to pass key/mouse events through to the ButtonThrower (so that no global events will be generated either).

The problem there is that there is twofold, I think: First, there are a number of places in which I’d have to put such code. And second, it wouldn’t affect the built-in behaviour–things like buttons highlighting when the mouse is over them–I believe.

Hmm… Would the fact that I have at least one other MouseWatcherNode present impact the results of this? For example, would it change the order in which they take effect, and would that change their behaviour…?

This is an intriguing option! I take it that such a region could be easily removed and re-added without significant consequence?

I don’t know how you have your MouseWatcherNodes configured or how you want them to behave; I am assuming you want to disable only one of them? If you use stash() and unstash(), I don’t believe the order of nodes is affected, but you can specify a sort value explicitly if you wanted to.

If stashing does what you want, it is simpler and more efficient than messing with regions.

Hmm… Okay, noted, and thank you. I’ll look into those options then, I intend! :slight_smile:

These are not mouse events, I think they are interface events.

Sure, but they’re driven by the mouse. I thus want to prevent them, not by tracking down each and every one and attempting to prevent it, but by cutting off their source.

Hmm, okay, follow-up:

If I “stash” “base.mouseWatcher”, I seem to lose keyboard events, which I do want to keep.

(Perhaps I should temporarily replace “base.mouseWatcher” with a keyboard-only watcher…?)

If I set up a new MouseWatcherRegion, it seems–at least under my current implementation–to have no apparent effect: I still get mouse-over effects from things like buttons.

In case I’m doing something wrong in the latter implementation, here is, roughly, what I’m doing:

In my setup code:

        # I'm presuming that the coordinates used match
        # those of "render2d". However, I've also tried
        # very high values (10000) to similar effect
        MenuController.mouseSuppressor = MouseWatcherRegion("mouse suppressor", -1, 1, -1, 1)
        # I want the suppression to initially be off, and to
        # not affect the keyboard
        MenuController.mouseSuppressor.setActive(False)
        MenuController.mouseSuppressor.setKeyboard(False)
        # And just to be safe, I'm giving this object a
        # high priority
        MenuController.mouseSuppressor.setSort(100)
        
        # Finally, I set the suppression-flags.
        # I haven't found a multi-flag example, so I'm
        # guessing somewhat at usage.
        MenuController.mouseSuppressor.setSuppressFlags(MouseWatcherRegion.SF_any_button | MouseWatcherRegion.SF_mouse_position)

When I “cease mouse mode”–i.e. enter “non-mouse mode”:

    MenuController.mouseSuppressor.setActive(True)

And when I “enter mouse mode”–i.e. exit “non-mouse mode”:

    MenuController.mouseSuppressor.setActive(False)

(Entering mouse-mode is driven by watching for movements of the mouse, or clicks of the mouse-buttons.)

[edit]
Okay, the creation of a new thrower/watcher seems to have done the job!

In short, this is what I now do:

In my setup code:

        MenuController.keyboardOnlyThrower = ButtonThrower("keyboardOnlyThrower")
        MenuController.keyboardOnlyWatcher = MouseWatcher("keyboardOnlyWatcher")
        MenuController.keyboardOnlyWatcher.addChild(MenuController.keyboardOnlyThrower)
        base.mouseWatcher.getParent().node().addChild(MenuController.keyboardOnlyWatcher)
        MenuController.keyboardOnlyNodePath = base.mouseWatcher.getParent().find("keyboardOnlyWatcher")
        MenuController.keyboardOnlyNodePath.stash()

When I “cease mouse mode”–i.e. enter “non-mouse mode”:

        Common.framework.mouseWatcher.stash()
        MenuController.keyboardOnlyNodePath.unstash()

And when I “enter mouse mode”–i.e. exit “non-mouse mode”:

        Common.framework.mouseWatcher.unstash()
        MenuController.keyboardOnlyNodePath.stash()

I’ll confess that I’m not clear on why this new watcher/thrower pair doesn’t produce the normal mouse-events–but it seems that it doesn’t. So, for now at least, it seems to be working!

1 Like