Skip to content

Commit d599b7d

Browse files
terrakokApoloApps
authored andcommitted
Web: deliver both scroll axes in wheel events (fix diagonal scroll) (JetBrains#3147)
Web: deliver both scroll axes in wheel events (fix diagonal scroll) Fixes https://youtrack.jetbrains.com/issue/CMP-10361 ## Testing Added a new test to validate diagonal scroll behavior. ## Release Notes ### Fixes - Web - Deliver both scroll axes in wheel events (fix diagonal scroll)
1 parent a6c4974 commit d599b7d

2 files changed

Lines changed: 41 additions & 7 deletions

File tree

compose/ui/ui/src/webMain/kotlin/androidx/compose/ui/window/ComposeWindowInternal.web.kt

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ import androidx.compose.ui.viewinterop.TrackInteropPlacementContainer
8888
import androidx.compose.ui.viewinterop.WebInteropContainer
8989
import androidx.lifecycle.Lifecycle
9090
import androidx.lifecycle.enableSavedStateHandles
91-
import kotlin.math.absoluteValue
9291
import kotlinx.browser.document
9392
import kotlinx.browser.window
9493
import kotlinx.coroutines.Dispatchers
@@ -746,14 +745,18 @@ internal class ComposeWindow(
746745
) {
747746
keyboardModeState = KeyboardModeState.Hardware
748747

749-
val horizontalScroll = when {
750-
event.deltaX.absoluteValue >= event.deltaY.absoluteValue -> event.deltaX
751-
event.shiftKey -> event.deltaY
752-
else -> 0f
748+
// Shift + mouse wheel means horizontal scroll. Some browsers swap the axes
749+
// for us (report deltaX instead of deltaY), some don't.
750+
val horizontalScroll: Double
751+
val verticalScroll: Double
752+
if (event.shiftKey && event.deltaX == 0.0) {
753+
horizontalScroll = event.deltaY
754+
verticalScroll = 0.0
755+
} else {
756+
horizontalScroll = event.deltaX
757+
verticalScroll = event.deltaY
753758
}
754759

755-
val verticalScroll = if (horizontalScroll == 0f) event.deltaY else 0f
756-
757760
// wheels event own buttons property is unreliable in Safari and Firefox
758761
// see CMP-9900 [web] Wheel event resolves buttons state incorrectly in Safari and Firefox
759762
val buttons = actualActivePointerButtons ?: event.composeButtons

compose/ui/ui/src/webTest/kotlin/androidx/compose/ui/window/WheelEventTests.kt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ import androidx.compose.runtime.CompositionLocalProvider
2929
import androidx.compose.runtime.InternalComposeApi
3030
import androidx.compose.ui.Modifier
3131
import androidx.compose.ui.OnCanvasTests
32+
import androidx.compose.ui.geometry.Offset
33+
import androidx.compose.ui.input.pointer.PointerEventType
34+
import androidx.compose.ui.input.pointer.pointerInput
3235
import androidx.compose.ui.platform.LocalDensity
3336
import androidx.compose.ui.unit.Density
3437
import androidx.compose.ui.unit.dp
@@ -234,6 +237,34 @@ class WheelEventTests : OnCanvasTests {
234237
}
235238

236239

240+
@Test
241+
fun diagonalScroll() = runTest {
242+
var totalScrollDelta = Offset.Zero
243+
createComposeWindow {
244+
Box(
245+
modifier = Modifier.size(100.dp).pointerInput(Unit) {
246+
awaitPointerEventScope {
247+
while (true) {
248+
val event = awaitPointerEvent()
249+
if (event.type != PointerEventType.Scroll) continue
250+
event.changes.forEach {
251+
totalScrollDelta += it.scrollDelta
252+
it.consume()
253+
}
254+
}
255+
}
256+
}
257+
)
258+
}
259+
260+
assertEquals(Offset.Zero, totalScrollDelta)
261+
262+
getCanvas().dispatchEvent(WheelEvent("wheel", WheelEventInit(deltaX = 5.0, deltaY = 7.0)))
263+
264+
assertEquals(5f, totalScrollDelta.x, "deltaX was expected to be delivered")
265+
assertEquals(7f, totalScrollDelta.y, "deltaY was expected to be delivered")
266+
}
267+
237268
@Test
238269
fun horizontalScrollWithShift() = runTest {
239270
val horizontalScrollState = ScrollState(initial = 0)

0 commit comments

Comments
 (0)