Re: Press ESC to exit()
Michael C <[email protected]> Tue, 02 May 2017 03:03:27 +0000
| Newsgroups | gmane.comp.python.ctypes,gmane.comp.python.tutor |
|---|---|
| Message-ID | <CANyKM1iDiogeOXB6oVYR7uj06806t++_G+PSnHeX853Chz2Kyw@mail.gmail.com> |
--===============8397792883042297903== Content-Type: multipart/alternative; boundary=001a1143ea4a45917a054e81c95c --001a1143ea4a45917a054e81c95c Content-Type: text/plain; charset=UTF-8 holy cow On Mon, May 1, 2017 at 8:02 PM eryk sun <[email protected]> wrote: > On Mon, May 1, 2017 at 6:28 PM, Michael C > <[email protected]> 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(). > --001a1143ea4a45917a054e81c95c Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div>holy cow=C2=A0</div><div><br><div class=3D"gmail_quote"><div>On Mon, M= ay 1, 2017 at 8:02 PM eryk sun <<a href=3D"mailto:[email protected]">ery= [email protected]</a>> wrote:<br></div><blockquote class=3D"gmail_quote" st= yle=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Mo= n, May 1, 2017 at 6:28 PM, Michael C<br> <<a href=3D"mailto:[email protected]" target=3D"_blank">mys= [email protected]</a>> wrote:<br> > Hi all, I found out that one way to press ESC to kill the script was t= o use<br> > my previous<br> > script language, AutoHotKey and this is how it works:<br> ><br> > AutoHotKey code<br> >=C2=A0 ## function that kills the window with title '*Python 3.6.1 = Shell*'<br> ><br> > kill()<br> > {<br> > WinKill, *Python 3.6.1 Shell*<br> > }<br> ><br> > ## When ESC is pressed, runs the function 'kill'<br> > Esc::kill()<br> ><br> > Yes, that's the entire script.<br> > Is there a way to write it in Python on windows?<br> <br> Instead of using a hotkey, you can set a global low-level keyboard<br> hook. Then optionally you can check for a particular foreground window<br> before handling the key. For example:<br> <br> =C2=A0 =C2=A0 import ctypes<br> =C2=A0 =C2=A0 import win32con<br> =C2=A0 =C2=A0 import win32gui<br> <br> =C2=A0 =C2=A0 from ctypes import wintypes<br> <br> =C2=A0 =C2=A0 user32 =3D ctypes.WinDLL('user32', use_last_error=3DT= rue)<br> <br> =C2=A0 =C2=A0 VK_ESCAPE =3D 0x1B<br> <br> =C2=A0 =C2=A0 LLKHF_EXTENDED=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D 0x000000= 01<br> =C2=A0 =C2=A0 LLKHF_LOWER_IL_INJECTED =3D 0x00000002<br> =C2=A0 =C2=A0 LLKHF_INJECTED=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D 0x000000= 10<br> =C2=A0 =C2=A0 LLKHF_ALTDOWN=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=3D 0x0= 0000020<br> =C2=A0 =C2=A0 LLKHF_UP=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =3D 0x00000080<br> <br> =C2=A0 =C2=A0 ULONG_PTR =3D wintypes.WPARAM<br> =C2=A0 =C2=A0 class KBDLLHOOKSTRUCT(ctypes.Structure):<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 _fields_ =3D (('vkCode',=C2=A0 =C2=A0 = =C2=A0 wintypes.DWORD),<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ('= ;scanCode',=C2=A0 =C2=A0 wintypes.DWORD),<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ('= ;flags',=C2=A0 =C2=A0 =C2=A0 =C2=A0wintypes.DWORD),<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ('= ;time',=C2=A0 =C2=A0 =C2=A0 =C2=A0 wintypes.DWORD),<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ('= ;dwExtraInfo', ULONG_PTR))<br> <br> =C2=A0 =C2=A0 HOOKPROC =3D ctypes.WINFUNCTYPE(wintypes.LPARAM, ctypes.c_int= ,<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 wintypes.WPARAM, wintypes.LPARAM)<br> <br> =C2=A0 =C2=A0 user32.SetWindowsHookExW.restype =3D wintypes.HHOOK<br> =C2=A0 =C2=A0 user32.SetWindowsHookExW.argtypes =3D (<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 ctypes.c_int,=C2=A0 =C2=A0 =C2=A0 =C2=A0# _In_ = idHook<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 HOOKPROC,=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0# _In_ lpfn<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 wintypes.HINSTANCE, # _In_ hMod<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 wintypes.DWORD)=C2=A0 =C2=A0 =C2=A0# _In_ dwThr= eadId<br> <br> =C2=A0 =C2=A0 user32.CallNextHookEx.restype =3D wintypes.LPARAM<br> =C2=A0 =C2=A0 user32.CallNextHookEx.argtypes =3D (<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 wintypes.HHOOK,=C2=A0 # _In_opt_ hhk<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 ctypes.c_int,=C2=A0 =C2=A0 # _In_=C2=A0 =C2=A0 = =C2=A0nCode<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 wintypes.WPARAM, # _In_=C2=A0 =C2=A0 =C2=A0wPar= am<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 wintypes.LPARAM) # _In_=C2=A0 =C2=A0 =C2=A0lPar= am<br> <br> =C2=A0 =C2=A0 def keyboard_hook(handler, hwnd=3DNone):<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 @HOOKPROC<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 def hookfunc(nCode, wParam, lParam):<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 event =3D KBDLLHOOKSTRUCT.from_ad= dress(lParam)<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if hwnd is not None and win32gui.= GetForegroundWindow() =3D=3D hwnd:<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 handler(event)<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return user32.CallNextHookEx(hHoo= k, nCode, wParam, lParam)<br> <br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 hHook =3D user32.SetWindowsHookExW(win32con.WH_= KEYBOARD_LL, hookfunc,<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 None,= 0)<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 if not hHook:<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 raise ctypes.WinError(ctypes.get_= last_error())<br> <br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 win32gui.PumpMessages()<br> <br> =C2=A0 =C2=A0 if __name__ =3D=3D '__main__':<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 import msvcrt<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 import threading<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 import win32console<br> <br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 print('Press escape to quit')<br> <br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 def escape_handler(event):<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if event.vkCode =3D=3D VK_ESCAPE:= <br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 # kill the hook thr= ead<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 win32gui.PostQuitMe= ssage(0)<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 elif not (event.flags & LLKHF= _UP):<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 print('Virtual = Key Code: {:#04x} [{}]'.format(event.vkCode,<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 event= .time))<br> <br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 t =3D threading.Thread(target=3Dkeyboard_hook, = args=3D(escape_handler,<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 win32console.GetCon= soleWindow()), daemon=3DTrue)<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 t.start()<br> <br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 # consume keyboard input<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 while t.is_alive():<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if msvcrt.kbhit():<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 msvcrt.getwch()<br> <br> The __main__ demo should be run as a console script. The keyboard hook<br> filters on the console window handle from GetConsoleWindow().<br> </blockquote></div></div> --001a1143ea4a45917a054e81c95c-- --===============8397792883042297903== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot --===============8397792883042297903== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ ctypes-users mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/ctypes-users --===============8397792883042297903==--