-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
Closed as not planned
Closed as not planned
Copy link
Labels
stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-replRelated to the interactive shellRelated to the interactive shelltype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
Summary
On Windows, when Python enters raw mode (via tty.setraw(), tty.setcbreak(), or the underlying msvcrt functions), it calls SetConsoleMode() and overwrites all existing console mode flags instead of preserving them. This breaks mouse input in TUI applications because ENABLE_MOUSE_INPUT and ENABLE_EXTENDED_FLAGS get wiped out.
Reproduction
import sys
import ctypes
if sys.platform == "win32":
kernel32 = ctypes.windll.kernel32
STD_INPUT_HANDLE = -10
ENABLE_MOUSE_INPUT = 0x0010
ENABLE_EXTENDED_FLAGS = 0x0080
handle = kernel32.GetStdHandle(STD_INPUT_HANDLE)
mode = ctypes.c_ulong()
# Get current mode and add mouse input
kernel32.GetConsoleMode(handle, ctypes.byref(mode))
print(f"Before: 0x{mode.value:04x}")
# Set mouse input flags
kernel32.SetConsoleMode(handle, mode.value | ENABLE_MOUSE_INPUT | ENABLE_EXTENDED_FLAGS)
kernel32.GetConsoleMode(handle, ctypes.byref(mode))
print(f"After adding mouse flags: 0x{mode.value:04x}")
# Now simulate what happens when a TUI library enters raw mode
# (This is what libraries like Textual do internally)
import msvcrt
import os
if hasattr(os, 'set_blocking'):
# On Python 3.5+, raw mode handling goes through here
pass
# Check mode after - mouse flags are typically gone
kernel32.GetConsoleMode(handle, ctypes.byref(mode))
print(f"After raw mode setup: 0x{mode.value:04x}")Real-World Impact
TUI frameworks like Textual are affected. When a Textual app starts:
- Textual sets console mode flags for mouse input
- Python/Textual enters raw mode for keyboard handling
- Raw mode setup calls
SetConsoleMode()with a fixed set of flags - Mouse input flags are wiped out
- Mouse selection, scrollbar, copy/paste stop working
This affects applications like:
- mistral-vibe (AI coding assistant)
- Any Textual-based TUI application on Windows
Expected Behavior
When Python enters raw mode, it should:
- Read current console mode with
GetConsoleMode() - Modify only the flags needed for raw mode
- Preserve existing flags like
ENABLE_MOUSE_INPUT
Actual Behavior
Raw mode setup overwrites the entire console mode, wiping out any flags previously set by the application.
Environment
- OS: Windows 10/11
- Python: 3.x (all versions with Windows console support)
- Terminal: Windows Terminal / ConHost
Suggested Fix
// Current approach (broken):
SetConsoleMode(handle, RAW_MODE_FLAGS);
// Fixed approach:
DWORD currentMode;
GetConsoleMode(handle, ¤tMode);
DWORD newMode = (currentMode & ~FLAGS_TO_CLEAR) | FLAGS_TO_SET;
SetConsoleMode(handle, newMode);Related Issues
This same bug exists in other runtimes:
- Node.js: Windows: setRawMode(true) overwrites console mode flags instead of preserving them nodejs/node#61161
- Bun: Windows: setRawMode(true) overwrites console mode flags instead of preserving them oven-sh/bun#25663
Workaround
Applications can re-apply console mode flags after entering raw mode:
def fix_windows_console_mode():
if sys.platform != "win32":
return
kernel32 = ctypes.windll.kernel32
handle = kernel32.GetStdHandle(-10)
mode = ctypes.c_ulong()
if kernel32.GetConsoleMode(handle, ctypes.byref(mode)):
kernel32.SetConsoleMode(handle, mode.value | 0x0010 | 0x0080)Metadata
Metadata
Assignees
Labels
stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-replRelated to the interactive shellRelated to the interactive shelltype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error