[Tutor] [ctypes-users] Press ESC to exit()
eryk sun
eryksun at gmail.com
Mon May 1 23:02:05 EDT 2017
On Mon, May 1, 2017 at 6:28 PM, Michael C
<mysecretrobotfactory at gmail.com> wrote:
> Hi all, I found out that one way to press ESC to kill the script was to use
> my previous
> script language, AutoHotKey and this is how it works:
>
> AutoHotKey code
> ## function that kills the window with title '*Python 3.6.1 Shell*'
>
> kill()
> {
> WinKill, *Python 3.6.1 Shell*
> }
>
> ## When ESC is pressed, runs the function 'kill'
> Esc::kill()
>
> Yes, that's the entire script.
> Is there a way to write it in Python on windows?
Instead of using a hotkey, you can set a global low-level keyboard
hook. Then optionally you can check for a particular foreground window
before handling the key. For example:
import ctypes
import win32con
import win32gui
from ctypes import wintypes
user32 = ctypes.WinDLL('user32', use_last_error=True)
VK_ESCAPE = 0x1B
LLKHF_EXTENDED = 0x00000001
LLKHF_LOWER_IL_INJECTED = 0x00000002
LLKHF_INJECTED = 0x00000010
LLKHF_ALTDOWN = 0x00000020
LLKHF_UP = 0x00000080
ULONG_PTR = wintypes.WPARAM
class KBDLLHOOKSTRUCT(ctypes.Structure):
_fields_ = (('vkCode', wintypes.DWORD),
('scanCode', wintypes.DWORD),
('flags', wintypes.DWORD),
('time', wintypes.DWORD),
('dwExtraInfo', ULONG_PTR))
HOOKPROC = ctypes.WINFUNCTYPE(wintypes.LPARAM, ctypes.c_int,
wintypes.WPARAM, wintypes.LPARAM)
user32.SetWindowsHookExW.restype = wintypes.HHOOK
user32.SetWindowsHookExW.argtypes = (
ctypes.c_int, # _In_ idHook
HOOKPROC, # _In_ lpfn
wintypes.HINSTANCE, # _In_ hMod
wintypes.DWORD) # _In_ dwThreadId
user32.CallNextHookEx.restype = wintypes.LPARAM
user32.CallNextHookEx.argtypes = (
wintypes.HHOOK, # _In_opt_ hhk
ctypes.c_int, # _In_ nCode
wintypes.WPARAM, # _In_ wParam
wintypes.LPARAM) # _In_ lParam
def keyboard_hook(handler, hwnd=None):
@HOOKPROC
def hookfunc(nCode, wParam, lParam):
event = KBDLLHOOKSTRUCT.from_address(lParam)
if hwnd is not None and win32gui.GetForegroundWindow() == hwnd:
handler(event)
return user32.CallNextHookEx(hHook, nCode, wParam, lParam)
hHook = user32.SetWindowsHookExW(win32con.WH_KEYBOARD_LL, hookfunc,
None, 0)
if not hHook:
raise ctypes.WinError(ctypes.get_last_error())
win32gui.PumpMessages()
if __name__ == '__main__':
import msvcrt
import threading
import win32console
print('Press escape to quit')
def escape_handler(event):
if event.vkCode == VK_ESCAPE:
# kill the hook thread
win32gui.PostQuitMessage(0)
elif not (event.flags & LLKHF_UP):
print('Virtual Key Code: {:#04x} [{}]'.format(event.vkCode,
event.time))
t = threading.Thread(target=keyboard_hook, args=(escape_handler,
win32console.GetConsoleWindow()), daemon=True)
t.start()
# consume keyboard input
while t.is_alive():
if msvcrt.kbhit():
msvcrt.getwch()
The __main__ demo should be run as a console script. The keyboard hook
filters on the console window handle from GetConsoleWindow().
More information about the Tutor
mailing list