How to get out of a loop with hotkeys

Asked

Viewed 1,262 times

4

I have an app that runs in the background in an infinite loop. How do I stop the loop using hotkeys (Ctrl+F1~F12)?

  • What you’ve already done?

  • Ever thought of using multithreading? I posted below responding literally to what was asked, but I’m not sure if this is the best way to do it.

  • @Maiconcarraro I’m making an improved version thereof, remaining only, stop the program.

  • @mgibsonbr I will study on multithreading. Grateful

1 answer

5


First, you need a way to detect that the user is trying to press a key without actually reading that key (otherwise, the loop would stop and wait for the user input). According to that question on Soen, this is done through the module select or - as the relevant function is not supported in Windows - msvcrt.kbhit.

Windows

An example in Windows would be:

>>> indice = 0
>>> while not msvcrt.kbhit() and indice < 1000000:
...   indice = indice + 1
...
_

(the cursor keeps blinking, but the loop keeps running, until the user type any key)

>>> indice
401247

As to detect hotkeys, what I realized in my tests (I don’t know if it’s the best way to do it) is that if you try to read the user input using msvcrt.getch (still on Windows) after such a sequence, it will give \x00 (F1 to F10) or \xe0 (F11 and F12):

>>> msvcrt.getch()
'\x00'

And if you try to read again, then it will generate a second character, depending on the sequence typed:

Ctrl + F1

>>> msvcrt.getch()
'\x00'
>>> msvcrt.getch()
'^'    

Ctrl + F10

>>> msvcrt.getch()
'\x00'
>>> msvcrt.getch()
'g'    

Ctrl + F12

>>> msvcrt.getch()
'\xe0'
>>> msvcrt.getch()
'\x8a'

Etc.

F1      F2      F3      F4      F5      F6
'\x00^' '\x00_' '\x00`' '\x00a' '\x00b' '\x00c'

F7      F8      F9      F10     F11        F12
'\x00d' '\x00e' '\x00f' '\x00g' '\xe0\x89' '\xe0\x8a'

The complete code would then be:

while True:
    # Faz alguma coisa

    if msvcrt.kbhit():
        a = msvcrt.getch()
        b = msvcrt.getch() if msvcrt.kbhit() else None
        if a == '\x00' and b == '^': # Ctrl + F1
            break

POSIX

On Linux (and presumably also on Mac) the solution involves select to make Polling of the keyboard, and termios to get the keys pressed (as detailed in that reply of mine to a related question):

>>> import sys, tty, termios, select
>>> def getch():
...   fd = sys.stdin.fileno()
...   old_settings = termios.tcgetattr(fd)
...   try:
...     tty.setraw(fd)
...     ch = sys.stdin.read(1)
...   finally:
...     termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
...   return ch
... 
>>> def kbhit():
...   fd = sys.stdin.fileno()
...   old_settings = termios.tcgetattr(fd)
...   try:
...     tty.setraw(fd)
...     i,o,e = select.select([sys.stdin],[],[],0.0001)
...     for s in i:
...       if s == sys.stdin:
...         return True
...     return False
...   finally:
...     termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
... 
>>> while True:
...   # Faz alguma coisa
...   if kbhit():
...     if getch() == '\x1b':
...       a, b, c, d = getch(), getch(), getch(), getch()
...       if a == '[' and b == '1' and c == '1' and d == '~': # Ctrl + F1
...         break
... 
>>>

In my tests he generated 5 characters, the first always \x1b and the following 4 in this way:

F1:  [ 1 1 ~
F2:  [ 1 2 ~
F3:  [ 1 3 ~
F4:  [ 1 4 ~
F5:  [ 1 5 ~
F6:  [ 1 7 ~
F7:  [ 1 8 ~
F8:  [ 1 9 ~
F9:  [ 2 0 ~
F10: [ 2 1 ~
F11: [ 2 3 ~
F12: [ 2 4 ~

Reiterating, I do not know if this is the best way, nor if it is portable. But it worked successfully in my tests on Windows 7 and Ubuntu.

  • I’m on Linux, but I appreciate the help.

  • @Fernandogomes I kind of got a solution for Linux too, I’m testing here at Vagrant to make sure it works and soon update the answer.

  • @Fernandogomes Ready to go! Just be careful not to make a mistake when typing the code, because I did it and I blocked my terminal, I needed to end the SSH session "pulling the plug" hehe. P.S. In the future, wait a little longer before marking an answer as accepted, will appear someone with a better answer... :)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.