Break loop using hotkey - python

There are hundreds of similar questions but none of them appear to be a solution in my case.
My code is shaped in this way
def iterative_func():
# do things
while True:
iterative_func()
Then I would like it to stop when I press a hotkey let's say 'ctrl+k'.
I tried pynput but the listener is not applicable since it waits for an Input and the rest of the script (iterative_func()) won't run, in my case the script should continuously run until I press some hotkey.
Also the solution
while True:
try:
iterative_func()
except KeyboardInterrupt:
break
doesn't work for me (I don't know why, but maybe it's because I'm running VSCode), anyway it's not code I want to implement because the script will be deployed as a .exe file.
PS.
I cannot import Key and Controller from pynput, it prompts an error and I have no clue on how to fix this so also solutions using these should be avoided.

I tried pynput but the listener is not applicable since it waits for
an Input and the rest of the script (iterative_func()) won't run
I can shed some light on how to overcome this problem, which made you optout pynput. See the below approach:
from pynput import keyboard
running = True # flag on loop runs
def stop_run(): # function to stop the program
global running
running = False
# register a hotkey, and call stop_run() when it is pressed
with keyboard.GlobalHotKeys({'<ctrl>+k': stop_run}) as h:
while running:
print("Running ... ")
This will run your code and wait for hotkey to stop the loop by a flag.

Related

How to exit a Python program or loop via keybind or macro? Keyboardinterrupt not working

I am trying to complete a simple GUI automation program that merely opens a web page and then clicks on a specific spot on the page every 0.2 seconds until I tell it to stop. I want my code to run and have its loop run infinitely until a keybind I specify breaks the loop (or entire program). I started out with the classic, KeyboardInterrupt, which enables CTRL+C to exit a program. Here is what I thought my final code would look like:
import webbrowser, pyautogui, time
webbrowser.open('https://example.com/')
print('Press Ctrl-C to quit.')
time.sleep(5)
#pyautogui.moveTo(1061, 881)
try:
while True:
time.sleep(0.2)
pyautogui.click(1061,881)
except KeyboardInterrupt:
print('\nDone.')
Everything about the code works, except the fact that I can't exit it once the clicking loop starts. Keyboard interrupt and using CTRL-C to exit do not work at all for this script, for whatever reason.
I merely want to be able to press "escape" (or any other key) to exit the loop (or the program altogether) - just any way to make the loop exit and stop. Right now it runs ad infinitum, but I want a simple keybind macro to be able to stop/break it.
I've tried using getch to keybind the escape key to cause a break, but to no avail:
import webbrowser, pyautogui, time, msvcrt
webbrowser.open('https://example.com')
print('Press Ctrl-C to quit.')
time.sleep(5)
#pyautogui.moveTo(1061, 881)
try:
while True:
time.sleep(0.2)
pyautogui.click(1061,881)
if msvcrt.kbhit():
key = ord(readch())
if key == 27:
break
I'm surprised it's been so hard to do this in Python. I've checked out a lot of similar problems across Stackoverflow, but with unsatisfactory answers, and none that solve my problem, unfortunately. I've been able to do things like this in simpler coding languages like AuotHotKeys with ease. I feel like I'm dancing around the solution. Any and all help would be wonderfully appreciated! Thanks in advance.
If I understood correctly, you want to be able to stop your program by pressing a key on your keyboard.
To make you create a thread that will check in background if you press the key in question.
A little example:
import threading, time
from msvcrt import getch
key = "lol"
def thread1():
global key
lock = threading.Lock()
while True:
with lock:
key = getch()
threading.Thread(target = thread1).start() # start the background task
while True:
time.sleep(1)
if key == "the key choosen":
# break the loop or quit your program
Hope its help.

Keypress detection

I've been trying to get keypresses to be detected in a Python program. I want to find a way to do this without using Tkinter, curses, or raw_input. Here's what I'm going at:
while True:
if keypressed==1:
print thekey
Does anyone know how this is possible?
Python has a keyboard module with many features. Install it, perhaps with this command:
pip3 install keyboard
Then use it in code like:
import keyboard #Using module keyboard
while True:#making a loop
try: #used try so that if user pressed other than the given key error will not be shown
if keyboard.is_pressed('a'): #if key 'a' is pressed
print('You Pressed A Key!')
break #finishing the loop
else:
pass
except:
break #if user pressed other than the given key the loop will break
You can set multiple Key Detection:
if keyboard.is_pressed('a') or keyboard.is_pressed('b') or keyboard.is_pressed('c'):
#then do this
I took the liberty of editing your question slightly so it makes sense and has an answer, at least on Windows. (IDLE only interacts with your keyboard by means of the tkinter interface to tk.) On Windows, the answer is to use the msvcrt module's console io functions
import msvcrt as ms
while True:
if ms.kbhit():
print(ms.getch())
For other systems, you will have to find the equivalent system-specific calls. For posix systems, these may be part of curses, which you said you did not to use, but I do not know.
These functions do not work correctly when the program is run is run from IDLE in its default mode. The same may be true for other graphics-mode IDEs.

Ending an infinite while loop

I currently have code that basically runs an infinite while loop to collect data from users. Constantly updating dictionaries/lists based on the contents of a text file. For reference:
while (True):
IDs2=UpdatePoints(value,IDs2)
time.sleep(10)
Basically, my problem is that I do not know when I want this to end, but after this while loop runs I want to use the information collected, not lose it by crashing my program. Is there a simple, elegant way to simply exit out of the while loop whenever I want? Something like pressing a certain key on my keyboard would be awesome.
You can try wrapping that code in a try/except block, because keyboard interrupts are just exceptions:
try:
while True:
IDs2=UpdatePoints(value,IDs2)
time.sleep(10)
except KeyboardInterrupt:
print('interrupted!')
Then you can exit the loop with CTRL-C.
You could use exceptions. But you only should use exceptions for stuff that isn't supposed to happen. So not for this.
That is why I recommand signals:
import sys, signal
def signal_handler(signal, frame):
print("\nprogram exiting gracefully")
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
you should put this on the beginning of your program and when you press ctrl+c wherever in your program it will shut down gracefully
Code explanation:
You import sys and signals.
Then you make a function that executes on exit. sys.exit(0) stops the programming with exit code 0 (the code that says, everything went good).
When the program get the SIGINT either by ctrl-c or by a kill command in the terminal you program will shutdown gracefully.
I think the easiest solution would be to catch the KeyboardInterrupt when the interrupt key is pressed, and use that to determine when to stop the loop.
except KeyboardInterrupt:
break
The disadvantage of looking for this exception is that it may prevent the user from terminating the program while the loop is still running.
I use python to track stock prices and submit automated buy/sell commands on my portfolio. Long story short, I wanted my tracking program to ping the data server for info, and place trades off of the information gathered, but I also wanted to save the stock data for future reference, on top of being able to start/stop the program whenever I wanted.
What ended up working for me was the following:
trigger = True
while trigger == True:
try:
(tracking program and purchasing program conditions here)
except:
trigger = False
print('shutdown initialized')
df = pd.DataFrame...
save all the datas
print('shutdown complete')
etc.
From here, while the program is in the forever loop spamming away requests for data from my broker's API, using the CTRL-C keyboard interrupt function toggles the exception to the try loop, which nullifies the while loop, allowing the script to finalize the data saving protocol without bringing the entire script to an abrupt halt.
Hope this helps!
Resultant
I would suggest using the try, except syntax within a loop if you are running on an IPYNB file in Google Colab or Jupyter, like:
while True:
try:
IDs2=UpdatePoints(value,IDs2)
time.sleep(10)
except KeyboardInterrupt:
break
except:
continue
the last except is for any other error if occurs the loop will resume
You can catch the KeyboardInterrupt error in Python:
try:
while 1>0:
IDs2=UpdatePoints(value,IDs2)
time.sleep(10)
except KeyboardInterrupt:
print('While loop ended!')
Also, instead of saying:
while True:
It looks more professional to use:
while 1>0:
To read more about Python Error handling (try, except, etc.):
https://www.w3schools.com/python/python_try_except.asp
or:
https://www.w3schools.com/python/gloss_python_try_finally.asp

keybord interrupt event listener

I have a problem with my script. i want do do an event listender for the whole script from beginning to the end.
if someone presses ctrl-c or something it should ignore, or end the scipt with an print.
I can show you my code if needed.
I tried signal and sys but I didnt know how to use it right
A simple approach for ending the script with a print could be to wrap the whole script in a try/except block:
import sys
try:
while 1:
print 'To infinity and beyond!'
# etc etc...
except KeyboardInterrupt:
print 'Handling the keyboard interrupt...'
The interrupt still kills the script, but I would think this is desired behaviour for any user; personally I wouldn't recommend trying to override it.

Scanning Keypress in Python

I have paused a script for lets say 3500 seconds by using time module for ex time.sleep(3500).
Now, my aim is to scan for keypresses while the script is on sleep, i mean its on this line.
Its like I want to restart the script if a "keypress Ctrl+R" is pressed.
For ex.. consider
#!/usr/bin/python
import time
print "Hello.. again"
while True:
time.sleep(3500)
Now while the code is at last line, If i press Ctrl+R, i want to re-print "Hello.. again" line.
I am aware that this does not fully answer your question, but you could do the following:
Put the program logic code in a function, say perform_actions. Call it when the program starts.
After the code has been run, start listening for an interrupt.
That is, the user must press ctrl+c instead of ctrl+r.
On receiving an interrupt, wait half a second; if ctrl+c is pressed again, then exit.
Otherwise, restart the code.
Thus one interrupt behaves as you want ctrl+r to behave. Two quick interrupts quit the program.
import time
def perform_actions():
print("Hello.. again")
try:
while True:
perform_actions()
try:
while True: time.sleep(3600)
except KeyboardInterrupt:
time.sleep(0.5)
except KeyboardInterrupt:
pass
A nice side-effect of using a signal (in this case SIGINT) is that you also restart the script through other means, e.g. by running kill -int <pid>.
You may want to use Tkinter {needs X :(}
#!/usr/bin/env python
from Tkinter import * # needs python-tk
root = Tk()
def hello(*ignore):
print 'Hello World'
root.bind('<Control-r>', hello)
root.mainloop() # starts an X widget
This script prints Hello World to the console if you press ctrl+r
See also Tkinter keybindings. Another solution uses GTK can be found here
in a for loop sleep 3500 times for 1 second checking if a key was pressed each time
# sleep for 3500 seconds unless ctrl+r is pressed
for i in range(3500):
time.sleep(1)
# check if ctrl+r is pressed
# if pressed -> do something
# otherwise go back to sleep

Categories

Resources