Scale mouse input for high-density windows

This commit is contained in:
caly committed 2026-08-22 15:32:27 +03:00
1 parent 0b7326d8d1
commit 497cf9ea6c
3 files changed
+75 -14

No files matched your search

+2 -1
View File
@@ -20,7 +20,8 @@ bool ConvertSdlEvent(SDL_Window* window, const SDL_Event& source,
destination->payload = QuitEvent{};
return true;
case SDL_EVENT_WINDOW_RESIZED:
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: {
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED: {
WindowResizedEvent resized;
if (!SDL_GetWindowSize(window, &resized.logical_width,
&resized.logical_height) ||
+30 -10
View File
@@ -32,6 +32,12 @@ RobloxInputDispatchResult Result(RobloxInputDispatchState state,
return {state, kind, std::move(status)};
}
float ScaleToSurfacePixels(float coordinate, int32_t logical_extent,
int32_t pixel_extent) {
return coordinate * static_cast<float>(pixel_extent) /
static_cast<float>(logical_extent);
}
} // namespace
AndroidKeyMapping MapSdlKeyToAndroid(uint32_t sdl_scancode) {
@@ -493,11 +499,19 @@ RobloxInputDispatchResult RobloxInputRouter::HandleMouseMotionLocked(
RobloxInputEventKind::kMouseMotion,
Unsupported("native mouse motion is unavailable"));
}
mouse_x_ = event.x;
mouse_y_ = event.y;
return NativeResultLocked(sink_.mouse_move(sink_.context, event.x, event.y,
event.delta_x, event.delta_y),
RobloxInputEventKind::kMouseMotion);
mouse_x_ = ScaleToSurfacePixels(event.x, snapshot_.viewport.logical_width,
snapshot_.viewport.pixel_width);
mouse_y_ = ScaleToSurfacePixels(event.y, snapshot_.viewport.logical_height,
snapshot_.viewport.pixel_height);
const float delta_x = ScaleToSurfacePixels(
event.delta_x, snapshot_.viewport.logical_width,
snapshot_.viewport.pixel_width);
const float delta_y = ScaleToSurfacePixels(
event.delta_y, snapshot_.viewport.logical_height,
snapshot_.viewport.pixel_height);
return NativeResultLocked(
sink_.mouse_move(sink_.context, mouse_x_, mouse_y_, delta_x, delta_y),
RobloxInputEventKind::kMouseMotion);
}
RobloxInputDispatchResult RobloxInputRouter::HandleMouseButtonLocked(
@@ -513,9 +527,11 @@ RobloxInputDispatchResult RobloxInputRouter::HandleMouseButtonLocked(
RobloxInputEventKind::kMouseButton,
Unsupported("SDL mouse button has no Android mapping"));
}
mouse_x_ = event.x;
mouse_y_ = event.y;
Status status = sink_.mouse_button(sink_.context, event.x, event.y,
mouse_x_ = ScaleToSurfacePixels(event.x, snapshot_.viewport.logical_width,
snapshot_.viewport.pixel_width);
mouse_y_ = ScaleToSurfacePixels(event.y, snapshot_.viewport.logical_height,
snapshot_.viewport.pixel_height);
Status status = sink_.mouse_button(sink_.context, mouse_x_, mouse_y_,
event.pressed, android_button);
if (status.ok()) {
const auto active = std::find(active_mouse_buttons_.begin(),
@@ -538,8 +554,12 @@ RobloxInputDispatchResult RobloxInputRouter::HandleMouseWheelLocked(
RobloxInputEventKind::kMouseWheel,
Unsupported("vertical native mouse wheel is unavailable"));
}
mouse_x_ = std::max(0.0f, event.mouse_x);
mouse_y_ = std::max(0.0f, event.mouse_y);
mouse_x_ = ScaleToSurfacePixels(
std::max(0.0f, event.mouse_x), snapshot_.viewport.logical_width,
snapshot_.viewport.pixel_width);
mouse_y_ = ScaleToSurfacePixels(
std::max(0.0f, event.mouse_y), snapshot_.viewport.logical_height,
snapshot_.viewport.pixel_height);
return NativeResultLocked(
sink_.mouse_wheel(sink_.context, mouse_x_, mouse_y_, event.delta_y),
RobloxInputEventKind::kMouseWheel);
+43 -3
View File
@@ -204,8 +204,13 @@ TEST_F(RobloxInputRouterTest, RoutesMouseMotionButtonAndVerticalWheel) {
.dispatched());
ASSERT_EQ(probe_.mouse_moves.size(), 1U);
EXPECT_FLOAT_EQ(probe_.mouse_moves[0].delta_x, 5.0f);
EXPECT_FLOAT_EQ(probe_.mouse_moves[0].x, 200.0f);
EXPECT_FLOAT_EQ(probe_.mouse_moves[0].y, 160.0f);
EXPECT_FLOAT_EQ(probe_.mouse_moves[0].delta_x, 10.0f);
EXPECT_FLOAT_EQ(probe_.mouse_moves[0].delta_y, -6.0f);
ASSERT_EQ(probe_.mouse_buttons.size(), 1U);
EXPECT_FLOAT_EQ(probe_.mouse_buttons[0].x, 200.0f);
EXPECT_FLOAT_EQ(probe_.mouse_buttons[0].y, 160.0f);
EXPECT_EQ(probe_.mouse_buttons[0].button, 1);
ASSERT_EQ(probe_.mouse_wheels.size(), 1U);
EXPECT_FLOAT_EQ(probe_.mouse_wheels[0].x, 0.0f);
@@ -213,6 +218,41 @@ TEST_F(RobloxInputRouterTest, RoutesMouseMotionButtonAndVerticalWheel) {
EXPECT_FLOAT_EQ(probe_.mouse_wheels[0].delta_y, -2.0f);
}
TEST_F(RobloxInputRouterTest,
ScalesMouseCoordinatesAfterDisplayScaleChange) {
const RobloxInputDispatchResult resize = router_.HandleEvent(
Event(platform::WindowResizedEvent{1000, 800, 1250, 1000}));
ASSERT_EQ(resize.state, RobloxInputDispatchState::kStateUpdated);
ASSERT_TRUE(router_
.HandleEvent(Event(platform::MouseMotionEvent{
400.0f, 240.0f, 8.0f, -4.0f, 0}))
.dispatched());
ASSERT_TRUE(router_
.HandleEvent(Event(platform::MouseButtonEvent{
true, SDL_BUTTON_LEFT, 1, 300.0f, 200.0f}))
.dispatched());
ASSERT_TRUE(router_
.HandleEvent(Event(
platform::MouseWheelEvent{0.0f, 2.0f, 600.0f, 400.0f}))
.dispatched());
ASSERT_EQ(probe_.mouse_moves.size(), 1U);
EXPECT_FLOAT_EQ(probe_.mouse_moves[0].x, 500.0f);
EXPECT_FLOAT_EQ(probe_.mouse_moves[0].y, 300.0f);
EXPECT_FLOAT_EQ(probe_.mouse_moves[0].delta_x, 10.0f);
EXPECT_FLOAT_EQ(probe_.mouse_moves[0].delta_y, -5.0f);
ASSERT_EQ(probe_.mouse_buttons.size(), 1U);
EXPECT_FLOAT_EQ(probe_.mouse_buttons[0].x, 375.0f);
EXPECT_FLOAT_EQ(probe_.mouse_buttons[0].y, 250.0f);
ASSERT_EQ(probe_.mouse_wheels.size(), 1U);
EXPECT_FLOAT_EQ(probe_.mouse_wheels[0].x, 750.0f);
EXPECT_FLOAT_EQ(probe_.mouse_wheels[0].y, 500.0f);
EXPECT_FLOAT_EQ(probe_.mouse_wheels[0].delta_y, 2.0f);
}
TEST_F(RobloxInputRouterTest, ScalesNormalizedTouchAndKeepsStablePointerIds) {
EXPECT_TRUE(router_
.HandleEvent(Event(platform::TouchEvent{
@@ -493,8 +533,8 @@ TEST_F(RobloxInputRouterTest,
ASSERT_TRUE(result.dispatched());
ASSERT_EQ(probe_.mouse_buttons.size(), 1U);
EXPECT_FLOAT_EQ(probe_.mouse_buttons[0].x, 321.0f);
EXPECT_FLOAT_EQ(probe_.mouse_buttons[0].y, 123.0f);
EXPECT_FLOAT_EQ(probe_.mouse_buttons[0].x, 642.0f);
EXPECT_FLOAT_EQ(probe_.mouse_buttons[0].y, 246.0f);
EXPECT_TRUE(probe_.mouse_buttons[0].pressed);
EXPECT_EQ(probe_.mouse_buttons[0].button, 0);
}