fix(input): map middle click to MouseButton3 (#171)

This commit is contained in:
farwhile authored and GitHub committed 2026-09-25 18:39:24 +03:00
1 parent 2eef4f966f
commit f07daccc82
4 files changed
+40 -19

No files matched your search

+4 -3
View File
@@ -40,9 +40,10 @@ struct AndroidKeyMapping {
// through with an ABI-incompatible numeric value.
AndroidKeyMapping MapSdlKeyToAndroid(uint32_t sdl_scancode, uint32_t sdl_key = 0);
// Mirrors the APK's MotionEvent.getActionButton() - 1 conversion. SDL button
// numbers are not numerically compatible with Android button bit values.
int32_t MapSdlMouseButtonToAndroid(uint8_t sdl_button);
// Translates SDL button numbers to the nativePassMouseButton argument.
// The first three are Roblox's zero-based MouseButton1/2/3 indices, not Android
// MotionEvent button bits.
int32_t MapSdlMouseButtonToRoblox(uint8_t sdl_button);
int32_t MapSdlGamepadButtonToAndroid(uint8_t sdl_button);
int32_t RobloxGamepadType(platform::GamepadFamily family);
+9 -8
View File
@@ -274,14 +274,15 @@ AndroidKeyMapping MapSdlKeyToAndroid(uint32_t sdl_scancode,
return {};
}
int32_t MapSdlMouseButtonToAndroid(uint8_t sdl_button) {
int32_t MapSdlMouseButtonToRoblox(uint8_t sdl_button) {
switch (sdl_button) {
case SDL_BUTTON_LEFT:
return 0;
case SDL_BUTTON_RIGHT:
return 1;
case SDL_BUTTON_MIDDLE:
return 3;
// MouseButton3 is index 2, not BUTTON_TERTIARY (4) minus one.
return 2;
case SDL_BUTTON_X1:
return 7;
case SDL_BUTTON_X2:
@@ -569,11 +570,11 @@ RobloxInputDispatchResult RobloxInputRouter::HandleMouseButtonLocked(
RobloxInputEventKind::kMouseButton,
Unsupported("native mouse buttons are unavailable"));
}
const int32_t android_button = MapSdlMouseButtonToAndroid(event.button);
if (android_button < 0) {
const int32_t roblox_button = MapSdlMouseButtonToRoblox(event.button);
if (roblox_button < 0) {
return Result(RobloxInputDispatchState::kIgnoredUnsupported,
RobloxInputEventKind::kMouseButton,
Unsupported("SDL mouse button has no Android mapping"));
Unsupported("SDL mouse button has no Roblox mapping"));
}
if (event.x > 0.0f || event.y > 0.0f ||
(mouse_x_ == 0.0f && mouse_y_ == 0.0f)) {
@@ -596,12 +597,12 @@ RobloxInputDispatchResult RobloxInputRouter::HandleMouseButtonLocked(
}
}
Status status = sink_.mouse_button(sink_.context, clamped_x, clamped_y,
event.pressed, android_button);
event.pressed, roblox_button);
if (status.ok()) {
const auto active = std::find(active_mouse_buttons_.begin(),
active_mouse_buttons_.end(), android_button);
active_mouse_buttons_.end(), roblox_button);
if (event.pressed && active == active_mouse_buttons_.end()) {
active_mouse_buttons_.push_back(android_button);
active_mouse_buttons_.push_back(roblox_button);
} else if (!event.pressed && active != active_mouse_buttons_.end()) {
active_mouse_buttons_.erase(active);
}
+1 -1
View File
@@ -325,7 +325,7 @@ TEST_F(RobloxInputNativeAdapterTest, CallsExactExportedJniSignatures) {
(std::vector<double>{90.0, 190.0, 4.0, -2.0}));
EXPECT_EQ(probe_.calls[1].name, "mouse-button");
EXPECT_EQ(probe_.calls[1].arguments,
(std::vector<double>{100.0, 200.0, JNI_TRUE, 3.0}));
(std::vector<double>{100.0, 200.0, JNI_TRUE, 2.0}));
EXPECT_EQ(probe_.calls[2].name, "touch");
EXPECT_EQ(probe_.calls[2].arguments,
(std::vector<double>{0.0, 320.0, 360.0, 0.0, 1280.0, 720.0}));
+26 -7
View File
@@ -170,13 +170,13 @@ class RobloxInputRouterTest : public ::testing::Test {
RobloxInputRouter router_{Sink(&probe_)};
};
TEST(RobloxInputMappingTest, MapsAndroidMouseButtonsExactlyLikeApk) {
EXPECT_EQ(MapSdlMouseButtonToAndroid(SDL_BUTTON_LEFT), 0);
EXPECT_EQ(MapSdlMouseButtonToAndroid(SDL_BUTTON_RIGHT), 1);
EXPECT_EQ(MapSdlMouseButtonToAndroid(SDL_BUTTON_MIDDLE), 3);
EXPECT_EQ(MapSdlMouseButtonToAndroid(SDL_BUTTON_X1), 7);
EXPECT_EQ(MapSdlMouseButtonToAndroid(SDL_BUTTON_X2), 15);
EXPECT_EQ(MapSdlMouseButtonToAndroid(42), -1);
TEST(RobloxInputMappingTest, MapsMouseButtonsForNativeInput) {
EXPECT_EQ(MapSdlMouseButtonToRoblox(SDL_BUTTON_LEFT), 0);
EXPECT_EQ(MapSdlMouseButtonToRoblox(SDL_BUTTON_RIGHT), 1);
EXPECT_EQ(MapSdlMouseButtonToRoblox(SDL_BUTTON_MIDDLE), 2);
EXPECT_EQ(MapSdlMouseButtonToRoblox(SDL_BUTTON_X1), 7);
EXPECT_EQ(MapSdlMouseButtonToRoblox(SDL_BUTTON_X2), 15);
EXPECT_EQ(MapSdlMouseButtonToRoblox(42), -1);
}
TEST(RobloxInputMappingTest, MapsSdlUsbKeysToLinuxAndAndroidCodes) {
@@ -238,6 +238,25 @@ TEST_F(RobloxInputRouterTest, RoutesMouseMotionButtonAndVerticalWheel) {
EXPECT_FLOAT_EQ(probe_.mouse_wheels[0].delta_y, -2.0f);
}
TEST_F(RobloxInputRouterTest, MiddleClickUsesMouseButton3OnPressAndRelease) {
ASSERT_TRUE(router_
.HandleEvent(Event(platform::MouseButtonEvent{
true, SDL_BUTTON_MIDDLE, 1, 100.0f, 80.0f}))
.dispatched());
EXPECT_EQ(router_.Snapshot().active_mouse_buttons, 1U);
ASSERT_TRUE(router_
.HandleEvent(Event(platform::MouseButtonEvent{
false, SDL_BUTTON_MIDDLE, 1, 100.0f, 80.0f}))
.dispatched());
ASSERT_EQ(probe_.mouse_buttons.size(), 2U);
EXPECT_TRUE(probe_.mouse_buttons[0].pressed);
EXPECT_EQ(probe_.mouse_buttons[0].button, 2);
EXPECT_FALSE(probe_.mouse_buttons[1].pressed);
EXPECT_EQ(probe_.mouse_buttons[1].button, 2);
EXPECT_EQ(router_.Snapshot().active_mouse_buttons, 0U);
}
TEST_F(RobloxInputRouterTest,
ScalesMouseCoordinatesAfterDisplayScaleChange) {
const RobloxInputDispatchResult resize = router_.HandleEvent(