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 &lt;<a href=3D"mailto:[email protected]">ery=
[email protected]</a>&gt; 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>
&lt;<a href=3D"mailto:[email protected]" target=3D"_blank">mys=
[email protected]</a>&gt; wrote:<br>
&gt; Hi all, I found out that one way to press ESC to kill the script was t=
o use<br>
&gt; my previous<br>
&gt; script language, AutoHotKey and this is how it works:<br>
&gt;<br>
&gt; AutoHotKey code<br>
&gt;=C2=A0 ## function that kills the window with title &#39;*Python 3.6.1 =
Shell*&#39;<br>
&gt;<br>
&gt; kill()<br>
&gt; {<br>
&gt; WinKill, *Python 3.6.1 Shell*<br>
&gt; }<br>
&gt;<br>
&gt; ## When ESC is pressed, runs the function &#39;kill&#39;<br>
&gt; Esc::kill()<br>
&gt;<br>
&gt; Yes, that&#39;s the entire script.<br>
&gt; 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(&#39;user32&#39;, 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 ((&#39;vkCode&#39;,=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 (&#39=
;scanCode&#39;,=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 (&#39=
;flags&#39;,=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 (&#39=
;time&#39;,=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 (&#39=
;dwExtraInfo&#39;, 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 &#39;__main__&#39;:<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(&#39;Press escape to quit&#39;)<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 &amp; LLKHF=
_UP):<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 print(&#39;Virtual =
Key Code: {:#04x} [{}]&#39;.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==--