Scroll Wheel in Lemur

Hi again, I want to use the scroll wheel of the mouse when I’m inside a Panel, but I don’t find how.

I tried with:

MouseEventControl.addListenersToSpatial(this, new BasicMouseListener() {
   @Override
    public void mouseMoved(com.jme3.input.event.MouseMotionEvent event, com.jme3.scene.Spatial target, com.jme3.scene.Spatial capture) {
       function(event.getDeltaWheel());
    }
});

But it’s always 0. I tried too with:

event.getWheel();

But again 0.

Did I miss something to do?

You should use the InputMapper. That’s one of the best feature of Lemur

        FunctionId f = new FunctionId("bla");
        GuiGlobals.getInstance().getInputMapper().map(f, Axis.MOUSE_WHEEL);
        GuiGlobals.getInstance().getInputMapper().addAnalogListener((func, value, tpf) -> {
            System.err.println("blabla");
        },f);

this prints “blabla” in the console when you use the mouse wheel
value is 1 when you scroll up, -1 when you scroll down

It’s weird though. I’ll have to look into why the regular mouse motion event is not getting passed through. I think I actually generate my own instead of using JME’s but I’d have to check.

In the mean time, you can use InputMapper to capture the events but I guess you will have to do some code gymnastics to get it to your panel.

It works fine :smiley: I just have to check if is inside the panel when I use the mouse wheel.

Thanks! :smiley:

However, It would be great that the MouseEventControl works with the wheel, it’s easier to use with Panels and Spatials :laughing:

Yes, absolutely. If you want you can submit a problem report in github. I will try to look at it the next time I’m able.

As mentioned in another thread, I’m throwing a big party at my house next week end so my free time is fully occupied these days. (Plus things keep breaking increasing my to-do list.)

Ok, I’ll do it.

Thanks for all, and cheer up! you are doing an amazing work with Lemur! :smiley:

Well, taking a look to the code, I can see that the MouseMotionEvent is always triggered with 0’s in the BasePickState (and there is no other appState throwing mouse events on lemur). The code (in PickEventSession) looks always like:

// MouseMotionEvent(int x, int y, int dx, int dy, int wheel, int deltaWheel)
event = new MouseMotionEvent((int)cursor.x, (int)cursor.y, 0, 0, 0, 0);

The methods firing this events are all submitted by a MouseObserver, which is defined in MouseAppState (extending BasePickState). The strange thing here is that the JME’s MouseMotionEvent is being ignored (commented) and motion is being handled with JME’s MouseButtonEvent. The code is as follows:

    @Override
    protected void dispatchMotion() {
        Vector2f cursor = getApplication().getInputManager().getCursorPosition();
        getSession().cursorMoved((int)cursor.x, (int)cursor.y);
    }

    protected void dispatch(MouseButtonEvent evt) {
        if( getSession().buttonEvent(evt.getButtonIndex(), evt.getX(), evt.getY(), evt.isPressed()) ) {
            evt.setConsumed();
        }
    }

    protected class MouseObserver extends DefaultRawInputListener {
        @Override
        public void onMouseMotionEvent( MouseMotionEvent evt ) {
            //if( isEnabled() )
            //    dispatch(evt);
        }

        @Override
        public void onMouseButtonEvent( MouseButtonEvent evt ) {
            if( isEnabled() ) {
                dispatch(evt);
            }
        }
    }

Instead, the dispatchMotion method is fired by the update(float) in BasePickState. I’m not fully aware about how the delta is handled for all this stuff (is it being calculated by JME or it is by hardware/driver?. Can be it just be done with an newX - oldX?, but then, how can that be done for the wheel, was it also giving values more than -1, 1? O.o).

So, I suppose the solution to this is coming from an implementation of it more than a fix.

(All this research is also revealing that CursorButtonEvent (the one being viewPort-aware) being fired by PickEventSession is passing the cursor’s x and y without adapting it to the viewPort position, so it would be as easy as subtracting this position to the coord values before passing them) - Problem post.

Which position? ViewPorts don’t have a position and the viewport settings of the camera are 0.0 to 1.0 in relation to 0,0 to width, height… so x, y cursor position should still hold.

I meant the camera associated to that viewport. If the viewport is using only a portion of the screen, the problem is that inside that viewport (and that viewport having it own rootNode and, this one being rendered on the Gui-bucket), if you put something at 0,0, it will be shown at the bottom left corner but the cursor position given by lemur would be another value than 0,0 for that corner (relative to it visual screen position).

Lets say that we have the “visual” case:

0,1080        1920,1080

0,800      ._____.
           |     |
           ._____.
0,0     800,0  1920,0

Where the “square” is the viewport. If you have a display ofr 1920x1080, the viewport there, somehow because of the gui-bucket, is managing also it coords from 0x → 1920x, 0y → 1080y. However, the x and y being passed by the cursor are from 800x → 1920x, 800y → 1080y.

Doing the mentioned subtract on the inside-viewport-events I can get the values for it in the desired range (which I think is the default desire but I can be wrong). This doesn’t fix the other problem though, in where the event isn’t being fired when the spatial inside the viewport is clicked but in an offset, even if that offset is outside the viewport (it seems that has something to do with the rays and I think that has something to do with the same coord things).

EDIT: The piece of code to be changed to this offset problem maybe would be:

protected Ray getPickRay( RootEntry rootEntry, Vector2f cursor ) {
......
        if( rootEntry.root instanceof Spatial && ((Spatial)rootEntry.root).getQueueBucket() == Bucket.Gui ) {
            // Special case for Gui Bucket nodes since they are always in screen space
            result = new Ray(new Vector3f(cursor.x, cursor.y, 1000), new Vector3f(0, 0, -1));
        }
......
}

to:

protected Ray getPickRay( RootEntry rootEntry, Vector2f cursor ) {
......
        if( rootEntry.root instanceof Spatial && ((Spatial)rootEntry.root).getQueueBucket() == Bucket.Gui ) {
            // Special case for Gui Bucket nodes since they are always in screen space
            result = new Ray(new Vector3f(cursor.x - Display.getWidth() * cam.getViewPortLeft(),
                                          cursor.y - Display.getHeight() * cam.getViewPortTop(), 1000),
                                          new Vector3f(0, 0, -1));
        }
......

Well, but the weird thing is that I’ve had 2D viewports in my own code that worked just fine.

Perhaps JME is doing something strange with the viewports with respect to the GUI bucket here, though. Else, the screen pixel coordinates should continue to be screen pixel coordinates in camera space… regardless of how the viewport is clipping them. That’s definitely the way it works in non GUI bucket code.

At least using cursorEventControl i cannot find a way to get mousewheel events (all others work), is this still to be done, or should it work?

It’s tricky to handle the mouse wheel because JME doesn’t give me a way to query it. I don’t actually handle mouse motion events as InputManager listeners and instead do my own per frame (sometimes less than per frame) management.

It needs to be added but I just wanted to provide context for why it isn’t trivial. To fix this, I have to add a RawInputListener that does nothing but accumulate a mouse wheel value… then in my mouse motion update I need to grab this and calculate a delta from last update. Then I can use this delta value in the events that are created… and I’d have to modify the cursor event to know about the delta.

It so happens that I’m neck deep in the pick event code at the moment so I could potentially knock this out for the next lemur release. (I’m trying to build a drag-and-drop solution and may make modifications to the event management as part of that but so far no.)

Edit: and note, while it would be super ugly, you could add a similar listener to your own code in the mean time if you need this right away and can’t wait.