[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