【发布时间】:2016-09-26 18:33:15
【问题描述】:
我想在运行 python 脚本时在控制台中强制使用 QuickEdit 模式,然后在终止之前将其禁用。有没有办法做到这一点?
【问题讨论】:
标签: python windows console prompt
我想在运行 python 脚本时在控制台中强制使用 QuickEdit 模式,然后在终止之前将其禁用。有没有办法做到这一点?
【问题讨论】:
标签: python windows console prompt
您可以使用ctypes 呼叫GetConsoleMode 和SetConsoleMode。
ctypes 定义:
import msvcrt
import atexit
import ctypes
from ctypes import wintypes
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
# input flags
ENABLE_PROCESSED_INPUT = 0x0001
ENABLE_LINE_INPUT = 0x0002
ENABLE_ECHO_INPUT = 0x0004
ENABLE_WINDOW_INPUT = 0x0008
ENABLE_MOUSE_INPUT = 0x0010
ENABLE_INSERT_MODE = 0x0020
ENABLE_QUICK_EDIT_MODE = 0x0040
ENABLE_EXTENDED_FLAGS = 0x0080
# output flags
ENABLE_PROCESSED_OUTPUT = 0x0001
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 # VT100 (Win 10)
def check_zero(result, func, args):
if not result:
err = ctypes.get_last_error()
if err:
raise ctypes.WinError(err)
return args
if not hasattr(wintypes, 'LPDWORD'): # PY2
wintypes.LPDWORD = ctypes.POINTER(wintypes.DWORD)
kernel32.GetConsoleMode.errcheck= check_zero
kernel32.GetConsoleMode.argtypes = (
wintypes.HANDLE, # _In_ hConsoleHandle
wintypes.LPDWORD,) # _Out_ lpMode
kernel32.SetConsoleMode.errcheck= check_zero
kernel32.SetConsoleMode.argtypes = (
wintypes.HANDLE, # _In_ hConsoleHandle
wintypes.DWORD,) # _Out_ lpMode
以下将底层 WinAPI 函数包装为 get_console_mode 和 set_console_mode。我将包装器限制为仅在控制台的活动输入缓冲区或活动输出缓冲区上运行,即\\.\CONIN$ 和\\.\CONOUT$。我认为这比不必担心文件描述符和句柄要简单。值得注意的是,sys.stdin 和 sys.stdout 可能会重定向到其他地方,C 运行时的标准 I/O FILE 流、文件描述符和您可以从 GetStdHandle 获得的 Windows 标准句柄也可能是这种情况。在这些情况下,您仍然可以打开 CONIN$ 和 CONOUT$,只要进程附加到控制台。
def get_console_mode(output=False):
'''Get the mode of the active console input or output
buffer. Note that if the process isn't attached to a
console, this function raises an EBADF IOError.
'''
device = r'\\.\CONOUT$' if output else r'\\.\CONIN$'
with open(device, 'r+') as con:
mode = wintypes.DWORD()
hCon = msvcrt.get_osfhandle(con.fileno())
kernel32.GetConsoleMode(hCon, ctypes.byref(mode))
return mode.value
def set_console_mode(mode, output=False):
'''Set the mode of the active console input or output
buffer. Note that if the process isn't attached to a
console, this function raises an EBADF IOError.
'''
device = r'\\.\CONOUT$' if output else r'\\.\CONIN$'
with open(device, 'r+') as con:
hCon = msvcrt.get_osfhandle(con.fileno())
kernel32.SetConsoleMode(hCon, mode)
update_console_mode结合了后面的功能,让你传入你要设置的flags和要修改的标志mask。这包括要清除的标志。它还允许通过注册atexit function 来恢复以前的模式。
def update_console_mode(flags, mask, output=False, restore=False):
'''Update a masked subset of the current mode of the active
console input or output buffer. Note that if the process
isn't attached to a console, this function raises an
EBADF IOError.
'''
current_mode = get_console_mode(output)
if current_mode & mask != flags & mask:
mode = current_mode & ~mask | flags & mask
set_console_mode(mode, output)
else:
restore = False
if restore:
atexit.register(set_console_mode, current_mode, output)
例子:
if __name__ == '__main__':
import os
import sys
import time
if sys.stderr is None:
os.close(2)
sys.stderr = open('stderr.txt', 'w', buffering=1)
print("%#06x, %#06x" % (get_console_mode(),
get_console_mode(output=True)))
flags = mask = ENABLE_EXTENDED_FLAGS | ENABLE_QUICK_EDIT_MODE
update_console_mode(flags, mask, restore=True)
print("%#06x, %#06x" % (get_console_mode(),
get_console_mode(output=True)))
time.sleep(10) # check console properties
【讨论】:
r 而不是 r+ 打开 CONIN$,否则我会遇到异常 File or stream is not seekable,使用新的 Windows 10 控制台。
对于任何试图仅对当前控制台禁用快速编辑和插入模式并且无法找到简单解决方案的人:
import ctypes
kernel32 = ctypes.windll.kernel32
kernel32.SetConsoleMode(kernel32.GetStdHandle(-10), 128)
【讨论】:
这对于尝试在 Windows 中仅启用和禁用快速编辑模式而不禁用其他功能的人可能会有所帮助。
def quickedit(enabled=1): # This is a patch to the system that sometimes hangs
import ctypes
'''
Enable or disable quick edit mode to prevent system hangs, sometimes when using remote desktop
Param (Enabled)
enabled = 1(default), enable quick edit mode in python console
enabled = 0, disable quick edit mode in python console
'''
# -10 is input handle => STD_INPUT_HANDLE (DWORD) -10 | https://docs.microsoft.com/en-us/windows/console/getstdhandle
# default = (0x4|0x80|0x20|0x2|0x10|0x1|0x40|0x200)
# 0x40 is quick edit, #0x20 is insert mode
# 0x8 is disabled by default
# https://docs.microsoft.com/en-us/windows/console/setconsolemode
kernel32 = ctypes.windll.kernel32
if enabled:
kernel32.SetConsoleMode(kernel32.GetStdHandle(-10), (0x4|0x80|0x20|0x2|0x10|0x1|0x40|0x100))
print("Console Quick Edit Enabled")
else:
kernel32.SetConsoleMode(kernel32.GetStdHandle(-10), (0x4|0x80|0x20|0x2|0x10|0x1|0x00|0x100))
print("Console Quick Edit Disabled")
quickedit(0) # Disable quick edit in terminal
只需禁用快速编辑的 0x40 标志
【讨论】: