o3de
o3de copied to clipboard
Linux: mouse_delta_x listens to the mouse wheel input
Describe the bug On Linux, mouse_delta_x Input listens to both the mouse X axis movement and the mouse wheel scrolling. Mouse wheel scrolling should be picked up only by the mouse_delta_z Input.
This issue does not occur on Windows.
Assets required
Script Canvas and Input Bindings shown on the image below are required to reproduce this issue:
Steps to reproduce
- Create an entity, add Script Canvas and Input components to it.
- Assign assets mentioned in the Assets required section to their respective components.
- Enter the Game Mode (for example Ctrl + G).
- Scroll the mouse wheel.
Expected behavior Nothing happens.
Actual behavior Script Canvas prints output to the Console.
Video
https://user-images.githubusercontent.com/86952082/222140406-25d5c95d-b617-4e75-9dad-6cc914c854f7.mp4
Found in Branch Development (a775010)
Commit ID from o3de/o3de Repository a775010c5c3ea6b067df2ef0a398fbe02bb54434
Desktop
- Device: PC
- OS: Linux
- Version: Ubuntu 22.04.1 LTS
- CPU AMD Ryzen 5 3600
- GPU NVIDIA GeForce RTX 2060 SUPER
- Memory 16GB
I can verify this also happens on my end, this has been the case in 2210, 2305, and 2310. And this issue is not isolated to just script canvas, it even occurs when using the Fly Camera component with the Starting Point Input gem disabled.
This happens on my end, but debugging into it, it seems like when I roll the mouse wheel, I get a xcb_input_raw_motion_event_t
with an axis value that is legitimate:
case XCB_INPUT_RAW_MOTION:
{
const xcb_input_raw_motion_event_t* mouseMotionEvent = reinterpret_cast<const xcb_input_raw_motion_event_t*>(event);
int axisLen = xcb_input_raw_button_press_axisvalues_length(mouseMotionEvent);
const xcb_input_fp3232_t* axisvalues = xcb_input_raw_button_press_axisvalues_raw(mouseMotionEvent);
for (int i = 0; i < axisLen; ++i)
{
const float axisValue = fp3232ToFloat(axisvalues[i]);
switch (i)
{
case 0:
QueueRawMovementEvent(InputDeviceMouse::Movement::X, axisValue);
break;
case 1:
QueueRawMovementEvent(InputDeviceMouse::Movement::Y, axisValue);
break;
}
}
}
```
It enters the Movement::X block... Note that this same thing happens when you move the mouse around horizontally. I'm not sure why I'm getting a horizontal axis event from XCB when I only roll the mouse wheel. Perhaps there is something else in the event that informs that its a wheel event
There's nothing in the event struct (I inspected it in the debugger) coming from XCB to discern between a mouse axis (x and y movement) and wheel event. The device id and other fields are identical. Maybe there's some way to discern in the XCB api?
What I'm seeing in the debugger is when you roll the mouse wheel and nothing else, we get an XCB generic event that is of type button press for the wheel axis, and then button release for the wheel axis, and then we get a raw motion event for button 0 as well (that is, event->detail is 0). The event contains 2 axes. Only the 0th axis moves.
The problem is that the same exact event happens if you move the mouse (raw motion event, with 2 axes, but these axes move).
The only thing that seems different between actual movement events and wheel events is that the event always seems to have 2 axes available in move events, and 1 axis available in wheel events. Could use this to discern between the two, but surely theres a better way to ask it what virtual axis it is, or button?
I think I figured it out. I'll upload a fix soon. It looks like in XCB (poorly documented) a xcb_input_raw_motion_event_t is also a raw button press, and inside that struct is a valuator bitmask. (A valuator is an axis of a device that isn't binary, such as a button press).
so this code should fix it
uint32_t mask = *(xcb_input_raw_button_press_valuator_mask(mouseMotionEvent));
if ((mask & 0x3) == 0)
{
// x and y movement are not present in the mask. This is not necessarily a wheel roll,
// but its also not x and y movement. What it is depends on how many axes the device actually has.
// Since we capture wheel roll as button presses (above), ignore this.
break;
}
```
The button press valuator mask will contain 0x1 (horizontal axis), 0x2 (vertical axis), or more typically in all the tests I did, (0x1 | 0x2) == 0x3, meaning, 2 axes have been updated and they are x and y axes. For all other motion events the valuator mask will contain different bits (for example if you have a mouse with a Z axis it may have 0x4). The mouse wheel appears to always report in as valuator 0x8.
Note that my solution was chosen since it impacts the smallest amount of code I could find.
Another solution would be to stop using the button press wheel and use the axis instead. Or add a new axis to the mouse input API in O3DE that represents 'smooth' scrolling from the axis rather than 'wheel clicks'.