Message243229
Testing getpass shouldn't be that difficult if you use ctypes to call WriteConsoleInput [1]. For example:
from ctypes import *
from ctypes.wintypes import *
kernel32 = WinDLL('kernel32')
IN, OUT, INOUT = 1, 2, 3
KEY_EVENT = 0x0001
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
STD_ERROR_HANDLE = -12
INVALID_HANDLE_VALUE = HANDLE(-1).value
class KEY_EVENT_RECORD(Structure):
class UCHAR(Union):
_fields_ = (('UnicodeChar', WCHAR),
('AsciiChar', CHAR))
_fields_ = (('bKeyDown', BOOL),
('wRepeatCount', WORD),
('wVirtualKeyCode', WORD),
('wVirtualScanCode', WORD),
('uChar', UCHAR),
('dwControlKeyState', DWORD))
class INPUT_RECORD(Structure):
class EVENT(Union):
_fields_ = (('KeyEvent', KEY_EVENT_RECORD),)
_fields_ = (('EventType', WORD),
('Event', EVENT))
PINPUT_RECORD = POINTER(INPUT_RECORD)
class HANDLE_IHV(HANDLE):
@classmethod
def _check_retval_(cls, retval):
if retval.value == INVALID_HANDLE_VALUE:
raise WinError(get_last_error())
return retval.value
def errcheck_bool(result, func, args):
if not result:
raise WinError(get_last_error())
return args
def WINAPI(name, dll, restype, *argspec):
if argspec:
argtypes = tuple(p[0] for p in argspec)
paramflags = tuple(p[1:] for p in argspec)
else:
argtypes = paramflags = ()
prototype = WINFUNCTYPE(restype, *argtypes, use_last_error=True)
func = prototype((name, dll), paramflags)
if restype in (BOOL, HANDLE):
func.errcheck = errcheck_bool
setattr(dll, name, func)
WINAPI('GetStdHandle', kernel32, HANDLE_IHV,
(DWORD, IN, 'nStdHandle'))
WINAPI('WriteConsoleInputW', kernel32, BOOL,
(HANDLE, IN, 'hConsoleInput'),
(PINPUT_RECORD, IN, 'lpBuffer'),
(DWORD, IN, 'nLength'),
(LPDWORD, OUT, 'lpNumberOfEventsWritten'))
def write_console_input(s):
hInput = kernel32.GetStdHandle(STD_INPUT_HANDLE)
recs = (INPUT_RECORD * len(s))()
for c, rec in zip(s, recs):
rec.EventType = KEY_EVENT
rec.Event.KeyEvent.bKeyDown = True
rec.Event.KeyEvent.wRepeatCount = 1
rec.Event.KeyEvent.uChar.UnicodeChar = c
return kernel32.WriteConsoleInputW(hInput, recs, len(recs))
if __name__ == '__main__':
import getpass
test_input = 'Console test input.\n'
n = write_console_input(test_input)
assert n == len(test_input)
read_input = getpass.getpass()
assert read_input == test_input.rstrip()
This requires that python.exe is run with an attached console (conhost.exe), i.e. the process can't be created as a DETACHED_PROCESS [2] nor can it be run using pythonw.exe without first calling AllocConsole.
[1]: https://msdn.microsoft.com/en-us/library/ms687403
[2]: https://msdn.microsoft.com/en-us/library/ms684863 |
|
Date |
User |
Action |
Args |
2015-05-14 23:05:33 | eryksun | set | recipients:
+ eryksun, tim.golden, r.david.murray, BreamoreBoy, python-dev, zach.ware, steve.dower, petrikas, Kain |
2015-05-14 23:05:33 | eryksun | set | messageid: <1431644733.4.0.584878723866.issue23995@psf.upfronthosting.co.za> |
2015-05-14 23:05:33 | eryksun | link | issue23995 messages |
2015-05-14 23:05:32 | eryksun | create | |
|