CCR/.venv/lib/python3.12/site-packages/progressbar/terminal/os_specific/windows.py

175 lines
4.4 KiB
Python

# ruff: noqa: N801
"""
Windows specific code for the terminal.
Note that the naming convention here is non-pythonic because we are
matching the Windows API naming.
"""
from __future__ import annotations
import ctypes
import enum
from ctypes.wintypes import (
BOOL as _BOOL,
CHAR as _CHAR,
DWORD as _DWORD,
HANDLE as _HANDLE,
SHORT as _SHORT,
UINT as _UINT,
WCHAR as _WCHAR,
WORD as _WORD,
)
_kernel32 = ctypes.windll.Kernel32 # type: ignore
_STD_INPUT_HANDLE = _DWORD(-10)
_STD_OUTPUT_HANDLE = _DWORD(-11)
class WindowsConsoleModeFlags(enum.IntFlag):
ENABLE_ECHO_INPUT = 0x0004
ENABLE_EXTENDED_FLAGS = 0x0080
ENABLE_INSERT_MODE = 0x0020
ENABLE_LINE_INPUT = 0x0002
ENABLE_MOUSE_INPUT = 0x0010
ENABLE_PROCESSED_INPUT = 0x0001
ENABLE_QUICK_EDIT_MODE = 0x0040
ENABLE_WINDOW_INPUT = 0x0008
ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200
ENABLE_PROCESSED_OUTPUT = 0x0001
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
DISABLE_NEWLINE_AUTO_RETURN = 0x0008
ENABLE_LVB_GRID_WORLDWIDE = 0x0010
def __str__(self) -> str:
return f'{self.name} (0x{self.value:04X})'
_GetConsoleMode = _kernel32.GetConsoleMode
_GetConsoleMode.restype = _BOOL
_SetConsoleMode = _kernel32.SetConsoleMode
_SetConsoleMode.restype = _BOOL
_GetStdHandle = _kernel32.GetStdHandle
_GetStdHandle.restype = _HANDLE
_ReadConsoleInput = _kernel32.ReadConsoleInputA
_ReadConsoleInput.restype = _BOOL
_h_console_input = _GetStdHandle(_STD_INPUT_HANDLE)
_input_mode = _DWORD()
_GetConsoleMode(_HANDLE(_h_console_input), ctypes.byref(_input_mode))
_h_console_output = _GetStdHandle(_STD_OUTPUT_HANDLE)
_output_mode = _DWORD()
_GetConsoleMode(_HANDLE(_h_console_output), ctypes.byref(_output_mode))
class _COORD(ctypes.Structure):
_fields_ = (('X', _SHORT), ('Y', _SHORT))
class _FOCUS_EVENT_RECORD(ctypes.Structure):
_fields_ = (('bSetFocus', _BOOL),)
class _KEY_EVENT_RECORD(ctypes.Structure):
class _uchar(ctypes.Union):
_fields_ = (('UnicodeChar', _WCHAR), ('AsciiChar', _CHAR))
_fields_ = (
('bKeyDown', _BOOL),
('wRepeatCount', _WORD),
('wVirtualKeyCode', _WORD),
('wVirtualScanCode', _WORD),
('uChar', _uchar),
('dwControlKeyState', _DWORD),
)
class _MENU_EVENT_RECORD(ctypes.Structure):
_fields_ = (('dwCommandId', _UINT),)
class _MOUSE_EVENT_RECORD(ctypes.Structure):
_fields_ = (
('dwMousePosition', _COORD),
('dwButtonState', _DWORD),
('dwControlKeyState', _DWORD),
('dwEventFlags', _DWORD),
)
class _WINDOW_BUFFER_SIZE_RECORD(ctypes.Structure):
_fields_ = (('dwSize', _COORD),)
class _INPUT_RECORD(ctypes.Structure):
class _Event(ctypes.Union):
_fields_ = (
('KeyEvent', _KEY_EVENT_RECORD),
('MouseEvent', _MOUSE_EVENT_RECORD),
('WindowBufferSizeEvent', _WINDOW_BUFFER_SIZE_RECORD),
('MenuEvent', _MENU_EVENT_RECORD),
('FocusEvent', _FOCUS_EVENT_RECORD),
)
_fields_ = (('EventType', _WORD), ('Event', _Event))
def reset_console_mode() -> None:
_SetConsoleMode(_HANDLE(_h_console_input), _DWORD(_input_mode.value))
_SetConsoleMode(_HANDLE(_h_console_output), _DWORD(_output_mode.value))
def set_console_mode() -> bool:
mode = (
_input_mode.value
| WindowsConsoleModeFlags.ENABLE_VIRTUAL_TERMINAL_INPUT
)
_SetConsoleMode(_HANDLE(_h_console_input), _DWORD(mode))
mode = (
_output_mode.value
| WindowsConsoleModeFlags.ENABLE_PROCESSED_OUTPUT
| WindowsConsoleModeFlags.ENABLE_VIRTUAL_TERMINAL_PROCESSING
)
return bool(_SetConsoleMode(_HANDLE(_h_console_output), _DWORD(mode)))
def get_console_mode() -> int:
return _input_mode.value
def set_text_color(color) -> None:
_kernel32.SetConsoleTextAttribute(_h_console_output, color)
def print_color(text, color) -> None:
set_text_color(color)
print(text) # noqa: T201
set_text_color(7) # Reset to default color, grey
def getch():
lp_buffer = (_INPUT_RECORD * 2)()
n_length = _DWORD(2)
lp_number_of_events_read = _DWORD()
_ReadConsoleInput(
_HANDLE(_h_console_input),
lp_buffer,
n_length,
ctypes.byref(lp_number_of_events_read),
)
char = lp_buffer[1].Event.KeyEvent.uChar.AsciiChar.decode('ascii')
if char == '\x00':
return None
return char