diff --git a/Lib/idlelib/idle_test/test_tree.py b/Lib/idlelib/idle_test/test_tree.py index b3e4c10cf9e38e..4bbe78e33638f5 100644 --- a/Lib/idlelib/idle_test/test_tree.py +++ b/Lib/idlelib/idle_test/test_tree.py @@ -32,27 +32,39 @@ def test_init(self): class TestScrollEvent(unittest.TestCase): def test_wheel_event(self): - # Fake widget class containing `yview` only. + # Fake widget class containing `xview` and `yview` only. class _Widget: - def __init__(widget, *expected): + def __init__(widget, direction, *expected): + widget.state = state widget.expected = expected + def xview(widget, *args): + self.assertEqual(widget.state&1, 1) + self.assertTupleEqual(widget.expected, args) def yview(widget, *args): + self.assertEqual(widget.state&1, 0) self.assertTupleEqual(widget.expected, args) # Fake event class class _Event: pass - # (type, delta, num, amount) - tests = ((EventType.MouseWheel, 120, -1, -5), - (EventType.MouseWheel, -120, -1, 5), - (EventType.ButtonPress, -1, 4, -5), - (EventType.ButtonPress, -1, 5, 5)) + # (type, delta, num, state, amount) + # If the first bit of state is set, scroll horizontally + tests = ((EventType.MouseWheel, 120, -1, 0, -5), + (EventType.MouseWheel, -120, -1, 0, 5), + (EventType.ButtonPress, -1, 4, 0, -5), + (EventType.ButtonPress, -1, 5, 0, 5), + (EventType.MouseWheel, 120, -1, 1, -5), + (EventType.MouseWheel, -120, -1, 1, 5), + (EventType.ButtonPress, -1, 4, 1, -5), + (EventType.ButtonPress, -1, 5, 1, 5)) event = _Event() - for ty, delta, num, amount in tests: + for ty, delta, num, state, amount in tests: event.type = ty event.delta = delta event.num = num - res = tree.wheel_event(event, _Widget(SCROLL, amount, "units")) + event.state = state + res = tree.wheel_event(event, + _Widget(state, SCROLL, amount, "units")) self.assertEqual(res, "break") diff --git a/Lib/idlelib/tree.py b/Lib/idlelib/tree.py index 182ce7189614da..2755b38ebfd55b 100644 --- a/Lib/idlelib/tree.py +++ b/Lib/idlelib/tree.py @@ -65,19 +65,25 @@ def wheel_event(event, widget=None): Macs use wheel down (delta = 1*n) to scroll up, so positive delta means to scroll up on both systems. + On both Windows and X-11, if the first bit of event.state is + set, it means that we should scroll horizontally not vertically. + X-11 sends Control-Button-4,5 events instead. The widget parameter is needed so browser label bindings can pass the underlying canvas. - This function depends on widget.yview to not be overridden by - a subclass. + This function depends on widget.xview/widget.yview to not be + overridden by a subclass. """ up = {EventType.MouseWheel: event.delta > 0, EventType.ButtonPress: event.num == 4} lines = -5 if up[event.type] else 5 widget = event.widget if widget is None else widget - widget.yview(SCROLL, lines, 'units') + if event.state&1: # If the first bit is set, scroll horizontally + widget.xview(SCROLL, lines, 'units') + else: + widget.yview(SCROLL, lines, 'units') return 'break' diff --git a/Misc/ACKS b/Misc/ACKS index 2dc513829a2218..465866444a93ee 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1942,6 +1942,7 @@ John Tromp Diane Trout Jason Trowbridge Steven Troxler +Daniel Tsvetkov Brent Tubbs Anthony Tuininga Erno Tukia diff --git a/Misc/NEWS.d/next/IDLE/2025-10-20-21-40-38.gh-issue-140389.vOs4uy.rst b/Misc/NEWS.d/next/IDLE/2025-10-20-21-40-38.gh-issue-140389.vOs4uy.rst new file mode 100644 index 00000000000000..2e48176610b81d --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2025-10-20-21-40-38.gh-issue-140389.vOs4uy.rst @@ -0,0 +1 @@ +Fixed trackpad scrolling direction in :mod:`IDLE `