https://github.com/python/cpython/commit/7f968a9c074cae8114e83507a0622ae259df2ca4 commit: 7f968a9c074cae8114e83507a0622ae259df2ca4 branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: terryjreedy <[email protected]> date: 2026-09-18T08:31:04Z summary:
[3.13] gh-56596: Make IDLE key bindings work with Caps Lock on (GH-157709) (#157739) gh-56596: Make IDLE key bindings work with Caps Lock on (GH-157709) Tk does not fold the case of letter keysyms, and Caps Lock changes it, so bind each key sequence with the other case of its letters too. --------- (cherry picked from commit 0b18efdf12c56b7b1f2080aa26c419b0014bde77) Co-authored-by: Serhiy Storchaka <[email protected]> Co-authored-by: Terry Jan Reedy <[email protected]> files: A Misc/NEWS.d/next/IDLE/2026-09-17-23-00-00.gh-issue-56596.capslock.rst M Lib/idlelib/editor.py M Lib/idlelib/idle_test/test_editor.py diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 8e15319b5baab2..1d5e181f42f764 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -34,6 +34,10 @@ TK_TABWIDTH_DEFAULT = 8 darwin = sys.platform == 'darwin' +# A letter keysym in a key sequence, such as "s" in "<Control-Key-s>". +_letter_key_re = re.compile(r'(?<=-Key-)[a-zA-Z](?=>)') + + class EditorWindow: is_shell = False # PyShell overrides. from idlelib.percolator import Percolator @@ -1186,6 +1190,12 @@ def apply_bindings(self, keydefs=None): for event, keylist in keydefs.items(): if keylist: text.event_add(event, *keylist) + # Caps Lock changes the case of letter keysyms, so bind + # the sequences with the other case too (gh-56596). + for keys in keylist: + other = _letter_key_re.sub(lambda m: m[0].swapcase(), keys) + if other not in keylist: + text.event_add(event, other) def fill_menus(self, menudefs=None, keydefs=None): """Fill in dropdown menus used by this window. diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index e32981091b72a6..2aaeb5037901b8 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -31,6 +31,26 @@ def test_init(self): self.assertEqual(e.root, self.root) e._close() + def test_apply_bindings_caps_lock(self): + # gh-56596: Caps Lock changes the case of letter keysyms, so the + # sequences are bound with both cases. + e = Editor(root=self.root) + try: + e.apply_bindings({'<<spam>>': ('<Control-Key-s>', '<Key-F1>'), + '<<eggs>>': ('<Control-Key-x><Alt-Shift-Key-S>',), + '<<ham>>': ('<Control-Key-h>', '<Control-Key-H>')}) + self.assertEqual(set(e.text.event_info('<<spam>>')), + {'<Control-KeyPress-s>', '<Control-KeyPress-S>', + '<KeyPress-F1>'}) + # Existing variants are not added again. + self.assertEqual(e.text.event_info('<<ham>>'), + ('<Control-KeyPress-h>', '<Control-KeyPress-H>')) + self.assertEqual(set(e.text.event_info('<<eggs>>')), + {'<Control-Key-x><Shift-Alt-Key-S>', + '<Control-Key-X><Shift-Alt-Key-s>'}) + finally: + e._close() + def test_set_width_zero_char_width(self): # A zero-width '0' must not raise ZeroDivisionError (gh-90304). e = Editor(root=self.root) diff --git a/Misc/NEWS.d/next/IDLE/2026-09-17-23-00-00.gh-issue-56596.capslock.rst b/Misc/NEWS.d/next/IDLE/2026-09-17-23-00-00.gh-issue-56596.capslock.rst new file mode 100644 index 00000000000000..70878e4f801263 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-09-17-23-00-00.gh-issue-56596.capslock.rst @@ -0,0 +1,2 @@ +Make IDLE keyboard shortcuts with ascii letters work when Caps Lock is on even when only one +of the upper and lowercase versions are defined. _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
