how to make program stop with a hotkey (outside the console) - python

I made an autoclicker and i can stop it by pressing b but only at the right timing. I didn't find anything that would allow me to stop the program by pressing a button at any time without accessing the console
Here's the program:
from time import sleep
import keyboard
import mouse
state=True
while state:
if keyboard.is_pressed("b"):
state=False
else:
mouse.click()
sleep(1)

I already answered at Using a key listener to stop a loop
You can simply use the add_hotkey method.
Example:
import keyboard
state = True
def stop():
state = False # The function you want to execute to stop the loop
keyboard.add_hotkey("b", stop) # add the hotkey

Related

Trying to accept the keyboard input 'R' alone or along side any other amount of keyboard inputs using either keyboard or pygame modules

import keyboard
import pygame
import mouse
import time
def press_X():
time.sleep(0.2)
keyboard.press('x')
time.sleep(0.6)
keyboard.release('x')
print('Command Executed - press_X')
#SA_R_X V_1.0
#------------------------------------------
while True:
try:
keyboard.add_hotkey('r', press_X)
time.sleep(0.5)
break
except:
keyboard.add_hotkey('r', press_X)
time.sleep(0.5)
break
the problem is the code cannot detect if 'r' is pressed when i am holding 'w' and/or 'space'... (well any key really)
I tried to use a try and except to handle a combination of any key + 'r'. But it did not work. All I need is for the code to be able to detect an 'r' input even if I am pressing/ holding another key at the same time. Then after this the code waits 0.2 seconds before holding down the 'x' key for 0.6 seconds and releasing. Any help is appreciated and it would be very helpful if you included a short explanation on where I went wrong and how you fixed it.
The documentation for this module can be found here. This is where all relevant information can be found.
The best way to do this, from my understanding, is to use an alternative function. If you want the program to continue to run, even though the key has not been pressed, then I suggest using the keyboard.on_press_key() function. This would mean that the rest of your program could still run, and your press_X() function could be run as a callback. Here is an example of how this code could be implemented.
import keyboard
import pygame
import mouse
import time
class App:
running = True
def press_X():
time.sleep(0.2)
keyboard.press('x')
time.sleep(0.6)
keyboard.release('x')
print('Command Executed - press_X')
App.running = False
#SA_R_X V_1.0
#------------------------------------------
keyboard.on_press_key('r', lambda x: press_X()) ## Adds an event listener for the r key
## This will stop execution if there is no code after this point
If you want it to stop the program and wait for the r key to be pressed, then you could use keyboard.wait(). This will basically pause your program until the key is pressed, after which your function would be run. For example, to replace the keyboard.on_press_key('r', lambda x: press_X()):
keyboard.wait('r')
press_X()
From my understanding, keyboard.add_hotkey() does not work in your situation because it is looking for an exact combination of keys being pressed, such as Ctrl+C, and will only go if only the keys in the hotkey are pressed.
I hope this helps, good luck!

Is there a way to mimic the effect of the time.sleep() function without pausing the entire program?

I am a new python 3.9 user who's trying to step up my coding. I'm writing a program that uses a while loop and will call functions to press keys based on user input. My code basically looks like:
from pynput.keyboard import Key, Controller
from graphics import *
import time
def wack():
M = Controller()
for i in range(3):
M.press('a')
time.sleep(1) # This guy right here is the issue
M.release('a')
def main():
click = Win.checkMouse()
while not click(click, exit_box):
click = Win.checkMouse()
if *input* == *correct string*:
wack()
I have a graphics window with an exit button and when exit is clicked, it terminates the program and closes the window. The issue is that the time.sleep(1) doesn't pause the inputs or that point in the code, it pauses the entire program suspending the while loop which is not what I want it to do.
Searching about the time function hasn't provided any clear solutions since time.sleep() seems to be the most popular pausing function in python.
asyncio is an amazing feature added in python3.7 which allows you to wait for an object or function(callled a coroutine in the context of asynchronous python) to get a result while the rest of the program executes.
asyncio has a sleep method which paused only the asynchronous function(coroutine) and lets the rest of the code in the program execute
This is how:
from pynput.keyboard import Key, Controller
from graphics import *
import time
import asyncio
#This is the asnychronous funtion
async def wack():
M = Controller()
for i in range(3):
M.press('a')
await asyncio.sleep(1)#this sleeps the function but allows the rest of the program to work
M.release('a')
def main():
click = Win.checkMouse()
while not click(click, exit_box):
click = Win.checkMouse()
if *input* == *correct string*:
asyncio.run(wack()) #calling the asynchronous funtion
Here is a tutorial on understanding asyn io for python

Python 3.x Collecting Mouse Events

I'm just trying to learn the "Listener" function. But I couldn't manage to break any loop with mouse clicking. Here is an example:
from pynput.mouse import Listener
import time
def on_click(x, y, button, pressed):
counter = 0
while True:
print(counter)
counter += 1
time.sleep(1)
if pressed:
break
with Listener(on_click = on_click) as listener:
listener.join()
When I'm running this code, my PC is getting very slow. I'm a beginner. I need to use listener with normal codes.
Thanks
Keep in mind that on_click function is called twice. Once when you press the mouse button down, and again when the button is released. Since the function will be called twice, we cannot break the loop that the first function call creates by calling it again with a different value for the state of the mouse button.
I am assuming your intention was to print counter every second the mouse button is held down. I have a snippet below for you that uses threading to accomplish this, and each call to the on_click function can read the state of the mouse as well as the state of the thread used for printing.
While using time.sleep() within a function it causes the thread it was called in to sleep. When you only have one thread running it causes the entire program to sleep every second. I believe that your computer was not lagging, however the mouse would appear to lag because your input is being interrupted by the call to sleep every second.
from pynput import mouse
import time
from threading import Thread
def on_click(x, y, button, pressed):
thread = Thread(target = threaded_function)
if pressed and thread.is_alive() == False:
thread.start()
if not pressed:
if thread.is_alive():
thread.join()
return False
def threaded_function():
count = 0
while True:
count+=1
print(count)
time.sleep(1)
with mouse.Listener(on_click = on_click) as listener:
listener.join()

Making A Bot In Python

I was making a bot that would basically keep the left mouse button clicked or unclicked based on a toggle. I get it to work but then it started lagging my entire computer so I didn't take it one step further, being scared to burn my PC, how It happened to my phone one year ago. So we are finally here asking you guys for some optimization to my project.
Code:
import keyboard
import win32api, win32con
from pynput.mouse import Button, Controller
mouse = Controller()
play=False
def toggle():
global play
if play==False:
play=True
else:
play=False
keyboard.add_hotkey('home',toggle)
played=False
while True:
if play==True and played==False:
played=True
mouse.press(Button.left)
elif play==False:
mouse.release(Button.left)
played=False
else:
pass
You should put a time.sleep() or something to wait between each loop because your while statement is running again and again without any pauses.
You can slow the while loop by inserting a sleep function in it. To do this, import the module time and call the function time.sleep(ms) in your while loop. It will be less reactive but you can set a sleep time of only a few ms and it will be better because the program will not be running at full speed all the time.

Unable To Break Out Of While Loop When Using Pynput.mouse

I have this relatively simple program that listens for mouse clicks and when the mouse button is held down prints "1"s. Unfortunately when I let go of the mouse it just keeps printing "1"s, even though there is an if statement which checks if the mouse is clicked and should stop the loop if it is not. I am using the pynput.mouse module for the mouse interaction.
Here is my code:
import time
from pynput.mouse import Listener
def clicked(x, y, button, pressed):
if pressed == True:
while button == button.left:
print("1")
time.sleep(1)
if pressed == False:
break
with Listener(on_click=clicked) as listener:
listener.join()
My theory is that once the loops starts it stops listening for mouse clicks, so it can never stop the loop. Would it be necessary to create a new thread for the loop? If yes, how would I do that?
Thanks!
Your current logic makes it impossible to get out of the loop, since pressed doesn't change within the loop. There is not a statement that checks if the mouse is clicked: your only if statements check whether the mouse was clicked when you entered the function. pressed doesn't change within the function.
Look at the critical logiic:
if pressed == True:
while ...
...
if pressed == False:
break
There is nothing in here to change the value of pressed; the first if guarantees that it's True anywhere within the loop.
Yes, you need to set up another listener that operates within the loop. You already know the building blocks: create a new one within the function and bind it to another operation that breaks the loop. For instance, you might "cheat" and have it reset pressed as a global variable.
You could also research how to do this in other answers, if you want an overall handler solution. keypress and keyrelease have been done often enough.
import pyautogui, random, time
import pynput
keys = ['w', 's', 'a', 'd']
def on_press(key):
p = True
if key == pynput.keyboard.Key.esc:
return False
else:
while p == True:
press = keys[random.randint(0,3)]
pyautogui.keyDown(press)
pyautogui.keyUp(press)
p = False
with pynput.keyboard.Listener(on_press=on_press) as L:
L.join()
a code like this will work instead of what you did.
BTW, that is just an example; feel free to visit my GitHub page: github.com/ironnicko

Categories

Resources