Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit b6720a5

Browse files
authored
Undo axes flip on Mac when shift+scroll-wheel (#38338)
* Undo axes flipping when using scroll wheel with shift key * Formatting * ++ * Fix test * Fix for test * Update shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm * ++ * Fix format * Review feedback
1 parent 9c0b187 commit b6720a5

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

shell/platform/darwin/macos/framework/Source/FlutterViewController.mm

+17-2
Original file line numberDiff line numberDiff line change
@@ -643,8 +643,23 @@ - (void)dispatchMouseEvent:(NSEvent*)event phase:(FlutterPointerPhase)phase {
643643
pixelsPerLine = 40.0;
644644
}
645645
double scaleFactor = self.flutterView.layer.contentsScale;
646-
flutterEvent.scroll_delta_x = -event.scrollingDeltaX * pixelsPerLine * scaleFactor;
647-
flutterEvent.scroll_delta_y = -event.scrollingDeltaY * pixelsPerLine * scaleFactor;
646+
// When mouse input is received while shift is pressed (regardless of
647+
// any other pressed keys), Mac automatically flips the axis. Other
648+
// platforms do not do this, so we flip it back to normalize the input
649+
// received by the framework. The keyboard+mouse-scroll mechanism is exposed
650+
// in the ScrollBehavior of the framework so developers can customize the
651+
// behavior.
652+
// At time of change, Apple does not expose any other type of API or signal
653+
// that the X/Y axes have been flipped.
654+
double scaledDeltaX = -event.scrollingDeltaX * pixelsPerLine * scaleFactor;
655+
double scaledDeltaY = -event.scrollingDeltaY * pixelsPerLine * scaleFactor;
656+
if (event.modifierFlags & NSShiftKeyMask) {
657+
flutterEvent.scroll_delta_x = scaledDeltaY;
658+
flutterEvent.scroll_delta_y = scaledDeltaX;
659+
} else {
660+
flutterEvent.scroll_delta_x = scaledDeltaX;
661+
flutterEvent.scroll_delta_y = scaledDeltaY;
662+
}
648663
}
649664
[_engine sendPointerEvent:flutterEvent];
650665

shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm

+21
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,27 @@ - (bool)testTrackpadGesturesAreSentToFramework {
629629
EXPECT_EQ(last_event.scroll_delta_x, -40 * viewController.flutterView.layer.contentsScale);
630630
EXPECT_EQ(last_event.scroll_delta_y, -80 * viewController.flutterView.layer.contentsScale);
631631

632+
// A discrete scroll event should use the PointerSignal system, and flip the
633+
// direction when shift is pressed.
634+
CGEventRef cgEventDiscreteShift =
635+
CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, 1, 0);
636+
CGEventSetType(cgEventDiscreteShift, kCGEventScrollWheel);
637+
CGEventSetFlags(cgEventDiscreteShift, kCGEventFlagMaskShift);
638+
CGEventSetIntegerValueField(cgEventDiscreteShift, kCGScrollWheelEventIsContinuous, 0);
639+
CGEventSetIntegerValueField(cgEventDiscreteShift, kCGScrollWheelEventDeltaAxis2,
640+
0); // scroll_delta_x
641+
CGEventSetIntegerValueField(cgEventDiscreteShift, kCGScrollWheelEventDeltaAxis1,
642+
2); // scroll_delta_y
643+
644+
called = false;
645+
[viewController scrollWheel:[NSEvent eventWithCGEvent:cgEventDiscreteShift]];
646+
EXPECT_TRUE(called);
647+
EXPECT_EQ(last_event.signal_kind, kFlutterPointerSignalKindScroll);
648+
// pixelsPerLine is 40.0, direction is reversed and axes have been flipped back.
649+
EXPECT_FLOAT_EQ(last_event.scroll_delta_x, 0.0 * viewController.flutterView.layer.contentsScale);
650+
EXPECT_FLOAT_EQ(last_event.scroll_delta_y,
651+
-80.0 * viewController.flutterView.layer.contentsScale);
652+
632653
// Test for scale events.
633654
// Start gesture.
634655
called = false;

0 commit comments

Comments
 (0)