[Tutor] [ctypes-users] Press ESC to exit()
Michael C
mysecretrobotfactory at gmail.com
Mon May 1 23:03:27 EDT 2017
holy cow
On Mon, May 1, 2017 at 8:02 PM eryk sun <eryksun at gmail.com> wrote:
> 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