Check for mouse press while mouse moves - python

I'm making a simple program that randomly moves my mouse to farm hours on sites like VHL. I want to add a section of code that stops the code from running when the mouse button is pressed.
So far I have this:
# imports
import random
import time
import pyautogui
# screen resolution - 2256, 1504
while True: # constantly runs, constantly updates variables
# vars that need to update part
posX = random.randint(0, 2256) # get a random x coordinate
posY = random.randint(0, 1504) # get a random y coordinate
randDuration = random.randint(2, 10) # get a random duration for mouse movement
randSleep = random.randint(5, 100) # get a random sleep time
# code part
pyautogui.moveTo(posX, posY, randDuration) # moves cursor to random coordinates from defined variables
print(f"Cursor moved to x:{posX} y:{posY} in {randDuration} seconds!")
time.sleep(randSleep)
from pynput.mouse import Listener
def is_clicked(x, y, button, pressed): # function that stops code after mouse1 is pressed
if pressed:
exit()
with Listener(on_click=is_clicked) as listener:
listener.join()
Everything works fine, but I want to be able to stop the program while the mouse is moving. In other words, while the line below runs:
pyautogui.moveTo(posX, posY, randDuration)
I want to simultaneously check if the mouse 1 button is being pressed.
Please let me know if you need any clarification. Thanks for the help.

Related

how do i keep a key pressed using pyautogui?

i am very new to coding and am making a macro for a game that after seing the specified color it will move the cursor to said color.
the code goes:
from time import sleep
import pyautogui
x=1
color = (166, 166, 61)
sleep(5)
while x==1:
s = pyautogui.screenshot()
pyautogui.keyDown("space")
for x in range(1171, 1172):
for y in range(544, 990):
if s.getpixel((x, y)) == color:
pyautogui.moveTo((x,y))
pyautogui.keyUp("space")
sleep(38)
the thing is that the space bar is not held like it would be if a player held it down as the menu connected to it doesn't open. Is there any way for me to simulate pressing the space bar so that it acts like it was pressed irl?

python - How to recognize images and click on them

I would like to make a script that clicks on images depending on what is asked, it needs to go trough a list of images. so for example if the user is asked by the program to click on the green circle:
question_list = greencircle, redcircle, bluesquare, redtriangle
if(greencircle == greencircle.png){
pyautogui.click(greencircle.png)
}
could someone help with this?
PyAutoGUI has a built in function called locateOnScreen() which returns the x, y coordinates of the center of the image if it can find it on the current screen (it takes a screenshot and then analyzes it).
The image has to match exactly for this to work; i.e. if you want to click on a button.png that button picture has to be the same exact size / resolution as the button in your windows for the program to recognize it. One way to achieve this is to take a screenshot, open it in paint and cut out only the button you want pressed (or you could have PyAutoGUI do it for you as I'll show in a later example).
import pyautogui
question_list = ['greencircle', 'redcircle', 'bluesquare', 'redtriangle']
user_input = input('Where should I click? ')
while user_input not in question_list:
print('Incorrect input, available options: greencircle, redcircle, bluesquare, redtriangle')
user_input = input('Where should I click?')
location = pyautogui.locateOnScreen(user_input + '.png')
pyautogui.click(location)
The above example requires you to already have greencircle.png and all the other .png in your directory
PyAutoGUI can also take screenshots and you can specify which region of the screen to take the shot pyautogui.screenshot(region=(0, 0, 0, 0)) The first two values are the x,y coordinates for the top left of the region you want to select, the third is how far to the right(x) and the fourth is how far down (y).
This following example takes a screenshot of the Windows 10 Logo, saves it to a file, and then clicks on the logo by using the specified .png file
import pyautogui
pyautogui.screenshot('win10_logo.png', region=(0, 1041, 50, 39))
location = pyautogui.locateOnScreen('win10_logo.png')
pyautogui.click(location)
You also don't have to save the screenshot to a file, you can just save it as a variable
import pyautogui
win10 = pyautogui.screenshot(region=(0, 1041, 50, 39))
location = pyautogui.locateOnScreen(win10)
pyautogui.click(location)
Making a program detect if a user has clicked in a certain area (let's say, the windows 10 logo) would require another library like pynput.
from pynput.mouse import Listener
def on_click(x, y, button, pressed):
if 0 < x < 50 and 1080 > y > 1041 and str(button) == 'Button.left' and pressed:
print('You clicked on Windows 10 Logo')
return False # get rid of return statement if you want a continuous loop
with Listener(on_click=on_click) as listener:
listener.join()
PUTTING IT ALL TOGETHER
import pyautogui
from pynput.mouse import Listener
win10 = pyautogui.screenshot(region=(0, 1041, 50, 39))
location = pyautogui.locateOnScreen(win10)
# location[0] is the top left x coord
# location[1] is the top left y coord
# location[2] is the distance from left x coord to right x coord
# location[3] is the distance from top y coord to bottom y coord
x_boundary_left = location[0]
y_boundary_top = location[1]
x_boundary_right = location[0] + location[2]
y_boundary_bottom = location[1] + location[3]
def on_click(x, y, button, pressed):
if x_boundary_left < x < x_boundary_right and y_boundary_bottom > y > y_boundary_top and str(button) == 'Button.left' and pressed:
print('You clicked on Windows 10 Logo')
return False # get rid of return statement if you want a continuous loop
with Listener(on_click=on_click) as listener:
listener.join()

Can't click on image again, what's wrong with my pygame code?

Okay, I'am trying to create a Tom and Jerry game with the pygame library.
The game focuses on catching mice by clicking on them as they appear in their holes. The problem
is that sometimes a cat appears instead of a mouse and should the player erroneously click on the
cat (s)he looses all earned points, but the game continues.
The mouse is an image of a mouse and the cat is an image of an cat.
If you click on the mouse, you get mouse, otherwise the cat gets the points.
The code is a mess, that's because I don't know what I'am doing and just set an another event loop because then it works, because it runs after I create the mouse. It works to click on the mouse but then you click somewhere else and after that it's like you did not clicked on the mouse.
The mouse is created in a loop and is supposed to wait for 5 seconds and if you click on the mouse within these seconds then an appropriate message prints out in the console ,,Jerry clicked!" else "1 click". If you don't click on the mouse within 5 seconds a image covers the mouse so she disappears.
Now, what I'am trying to do right now is to print the message 1 click when the player does not click on anything but print 1 click jerry clicked when the player clicks on the mouse. I have a image of the mousehole and then I put the mouse on the mousehole, that is, on an another image.
This code works with one image at least:
pygame.init()
width=350;
height=400
screen = pygame.display.set_mode( (width, height ) )
pygame.display.set_caption('clicked on image')
redSquare = pygame.image.load("images/red-square.png").convert()
x = 20; # x coordnate of image
y = 30; # y coordinate of image
screen.blit(redSquare , ( x,y)) # paint to screen
pygame.display.flip() # paint screen one time
running = True
while (running):
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
# Set the x, y postions of the mouse click
x, y = event.pos
if redSquare.get_rect().collidepoint(x, y):
print('clicked on image')
#loop over, quite pygame
pygame.quit()
My problem is that, when I click on the mouse and then I don't click on the mouse I can't click on the mouse again at another position.
So what's wrong? What I'am doing wrong here?
Here is my code:
import pygame
from pygame import *
from random import *
init()
run = True
screen = (800,800)
screen = display.set_mode(screen)
xpos = 0
ypos = 0
mouseorcatxpos = 5
mouseorcatypos = 0
mousehole = image.load("mousehole.png").convert()
cat = image.load("tom.png")
jerry = image.load("jerry.png")
def makeholes():
global ypos
global xpos
for holey in range(1,9):
for holex in range(1,9):
screen.blit(mousehole,(xpos,ypos))
display.flip()
xpos += 100
ypos += 100
xpos = 0
def mouseorcat():
global xpos
mouseorcatxpos = 5
ypos = 0
for mousecaty in range(1,9):
pygame.event.pump()
for mousecatx in range(1,9):
randommouse = randint(1, 3)
randomcat = randint(1, 10)
if(randommouse == 2):
screen.blit(jerry, (mouseorcatxpos, ypos))
display.flip()
for event in pygame.event.get():
if (event.type == MOUSEBUTTONDOWN):
if jerry.get_rect().collidepoint(xpos, ypos) == False:
print("l clicked!")
x, y = event.pos
if jerry.get_rect().collidepoint(xpos, y):
print("JERRY CLICKED!!")
x, y = event.pos
print(x, y)
time.wait(5000)
#screen.blit(mousehole, (mouseorcatxpos - 5, ypos))
display.flip()
elif(randomcat == 2):
screen.blit(cat, (mouseorcatxpos, ypos))
display.flip()
time.wait(1500)
screen.blit(mousehole, (mouseorcatxpos-5, ypos))
display.flip()
mouseorcatxpos += 100
mouseorcatxpos = 0
ypos += 100
makeholes()
while run == True:
for event in pygame.event.get():
mouseorcat()
if event.type == QUIT:
run = False
I rewrote your game to show you how I would do it.
To keep track of the time and to limit the framerate I used a pygame.time.Clock and a timer variable. The clock returns the time in milliseconds since clock.tick was called the last time, which is used to increase the timer variable. The cat just replaces the mouse after two seconds and the mouse is set to a new position. I use pygame.Rects to store the positions, but you could also use lists or tuples.
import sys
import random
import pygame
pygame.init()
size = (800, 800)
screen = pygame.display.set_mode(size)
# Images replaced by pygame.Surface. Do that too
# in the future before you post your code.
mousehole = pygame.Surface((40, 40)).convert()
mousehole.fill(pygame.Color(30, 30, 30))
cat = pygame.Surface((40, 40)).convert()
cat.fill(pygame.Color(110, 110, 130))
jerry = pygame.Surface((40, 40)).convert()
jerry.fill(pygame.Color(190, 130, 0))
# Create the background image and blit the holes.
background = pygame.Surface(size).convert()
for holey in range(8):
for holex in range(8):
background.blit(mousehole, (holex*100, holey*100))
def new_position():
"""Return a random position between 0-700 in steps of 100."""
return (random.randrange(0, 701, 100), random.randrange(0, 701, 100))
def main():
fps = 30
clock = pygame.time.Clock()
jerry_rect = jerry.get_rect() # Stores jerry's position and size.
jerry_rect.topleft = new_position() # New random position.
# The cat is outside of the screen first.
cat_rect = cat.get_rect(topleft=(-100, -100))
points = 0
timer = 0
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
if jerry_rect.collidepoint(event.pos):
points += 1
print('Jerry caught! Points:', points)
timer = 0
jerry_rect.topleft = new_position()
else:
print('Missed. Points:', points)
# Run logic.
timer += clock.tick(fps) / 1000 # timer + seconds since last tick.
if timer > 2: # Cat catches mouse after 2 seconds.
cat_rect.topleft = jerry_rect.topleft
jerry_rect.topleft = new_position()
timer = 0
points = 0
print('Tom caught Jerry.')
# Draw.
# Clear the screen by blitting the bg.
screen.blit(background, (0, 0))
screen.blit(jerry, jerry_rect)
screen.blit(cat, cat_rect)
pygame.display.flip()
if __name__ == '__main__':
main()
pygame.quit()
sys.exit()
Side notes:
Don't use star imports (from module import *), because that can make code harder to read. If you want you can use from pygame.locals import *, if it's the only star import.
Don't use global variables, because they can make code harder to read, understand and maintain. Pass variables to functions as arguments and then return the result.
Update: Some notes about your program:
The first big problem is that your game has two event loops and the important one is deeply nested inside of two other for loops and a if. The event loop should be directly under the main while loop (one indentation level (when you have more experience you can put it into a function or class method)).
The two for loops seem to have the purpose to let the code run until randommouse or randomcat are 2. To run code until a condition is met is the purpose of a while loop. But in this case you should better just pick a random number and write the if/elif conditions so that they always apply. For example, you want a 2/3 chance for mouse and 1/3 for a cat,
random_number = random.randint(1, 3)
if random_number < 3:
print("2/3 probability. It's a mouse")
else:
print("1/3 probability. It's a cat")
Or use random.choice with a list:
>>> random.choice(['mouse', 'mouse', 'cat'])
'mouse'
time.wait(5000) shouldn't be used because the game just hangs in this time. You can't even close the window. Limit the framerate and get the time since the last tick with a pygame.time.Clock.
pygame.event.pump() is not needed.
If you call get_rect() without an argument, the rect is positioned at (0, 0).
if jerry.get_rect().collidepoint(xpos, y):
That's the reason why clicking on jerry only works in the top row, and because you use the global xpos here. Since xpos is 0, the whole top row counts as Jerry.
You can pass coordinates to get_rect like so (you can also use center or other args instead of topleft):
jerry_rect = jerry.get_rect(topleft=(50, 100))
I'm sorry but I don't think I can simply fix your code. I've tried it several times, but I always end up re-writing it completely.
I begin by extracting the event loop out of the two nested for loops, then remove these loops, create rects for the mouse and cat, fix the collision detection, add a timer and so on. Take a close look at my example and try to rewrite your game in a similar way, and keep asking questions if you don't understand something.

Conceptual bug in a turtle program using resetscreen()

Criteria I'm trying to meet:
The screen resets when the user presses the SPACEBAR, meaning the drawn lines go away and the unnamed turtle returns to the center but it doesn’t return to the default turtle color and shape!
""" A simple drawing program
Click and drag the center turtle to draw
Click the colorful buttons to change the
turtle's color,
and then draw different shapes.
Press the SPACEBAR key to reset the
drawing.
"""
from turtle import *
turtle_1 = Turtle()
turtle_2 = Turtle()
turtle_3 = Turtle()
def callback_1(x,y):
color("red")
shape("circle")
circle(100)
def callback_2(x,y):
color("blue")
shape("square")
circle(100,steps=4)
def callback_3(x,y):
color("green")
shape("triangle")
circle(100,steps=3)
def place_turtles():
turtle_1.color("red")
turtle_1.shape("circle")
turtle_1.penup()
turtle_1.goto(-200,-200)
turtle_2.color("blue")
turtle_2.shape("square")
turtle_2.penup()
turtle_2.goto(0,-200)
turtle_3.color("green")
turtle_3.shape("triangle")
turtle_3.penup()
turtle_3.goto(200,-200)
def start_over():
resetscreen()
place_turtles()
listen()
onkey(start_over, "space")
ondrag(goto)
place_turtles()
This code allows the user to drag the turtle, press buttons, and reset the screen when they press SPACEBAR. For some reason, though, resetting the screen also resets the color of the turtle. How can I prevent this from happening?
Basically what I want to happen is if, say, the user clicks on the blue square button, then resets the screen to hide the shape drawn by the button, all of the turtles return to their original positions, but the unnamed turtle does not change its previous color and shape. Let me know if I need to elaborate further.
With a "better late than never" attitude, I believe I've reworked your code to get the behavior you desired. I also reworked your drag logic to give you better drawing capability:
from turtle import Turtle, Screen, getturtle
def callback_1(x, y):
anonymous.color(*turtle_1.color())
anonymous.shape(turtle_1.shape())
anonymous.circle(100)
def callback_2(x, y):
anonymous.color(*turtle_2.color())
anonymous.shape(turtle_2.shape())
anonymous.circle(100, steps=4)
def callback_3(x, y):
anonymous.color(*turtle_3.color())
anonymous.shape(turtle_3.shape())
anonymous.circle(100, steps=3)
def setup_turtles():
turtle_1.onclick(callback_1)
turtle_1.color("red")
turtle_1.penup()
turtle_1.goto(-200, -200)
turtle_2.onclick(callback_2)
turtle_2.color("blue")
turtle_2.penup()
turtle_2.goto(0, -200)
turtle_3.onclick(callback_3)
turtle_3.color("green")
turtle_3.penup()
turtle_3.goto(200, -200)
def start_over():
colors = anonymous.color()
anonymous.reset()
anonymous.color(*colors)
def drag_handler(x, y):
anonymous.ondrag(None) # disable event inside event handler
anonymous.goto(x, y)
anonymous.ondrag(drag_handler) # reenable event on event handler exit
anonymous = getturtle()
anonymous.ondrag(drag_handler)
turtle_1 = Turtle(shape="circle")
turtle_2 = Turtle(shape="square")
turtle_3 = Turtle(shape="triangle")
setup_turtles()
screen = Screen()
screen.onkey(start_over, "space")
screen.listen()
screen.mainloop()
Many of the changes are just for personal style reasons. The two key changes are: just reset the anonymous turtle itself, not the screen; rather than use goto as an event handler, wrap it in a function that turns off drag events during the goto call.

Pygame, Adding quit function to a rectangle

I have a problem I can't seem to solve. I have tried to find a way to add a function like quitting a program to a rectangle in Pygame. Here is the code I have so far. I would like to add an on click quit feature to the quit box in the corner.
def addRect(self):
self.rect = pygame.draw.rect(self.screen, (white), (300, 200, 300, 200), 2)
pygame.display.update()
def addText(self):
self.screen.blit(self.font.render('Quit', True, (84,84,84)), (550, 375))
pygame.display.update()
I have it working with the bits above and below and it does make a "Quit" Image at the bottom corner where I need it. However, I'm again stuck on the function!
I did something very similar to this, and the way that I handled it was I made a list in the main program that had all of the "inner windows" or whatever you want to call them. Whenever the main program received a signal from a window to close it, it deleted it from the list.
To make the signal, you will want to create a rect in the location where you want the button to be. Make a function for the "inner window" and have it test for that rect being clicked. If it is clicked, have the function return something like 'closed' or whatever you want. In the main program, say something like
for window in windows:
if window.update()=='closed':
windows.remove(window)
to remove any window which is closed.
EDIT:
After looking at your code a bit more in depth, it looks like how you're doing it won't work. To add a rect, you will need to have something in your main code to store whether or not the rect is there. To close the window, you will have to change that variable.
To check if the rect should be closed, make another rect that is where the text which should be closing the window is. When this text is clicked, have the function return something which should be interpreted by the main code to close the window.
A basic example is shown below.
The class:
def update(self):
#set up the test rect
text=self.font.render('Quit', True, (84,84,84))
textrect=text.get_rect()
textrect.topleft=(550, 375)
#see if the button is pressed
if textrect.collidepoint(pygame.mouse.get_pos()) and pygame.mouse.get_pressed()[0]:
return 'closed'
#render stuff
self.rect = pygame.draw.rect(self.screen, (white), (300, 200, 300, 200), 2)
self.screen.blit(text, (550, 375))
Note that I combined your two original classes into one, as I don't see a reason why you would ever want the rect but not the text or vise versa. This is a pretty simple change if you don't like it.
Also note that this will close the window if the mouse is pressed off the button, then dragged onto it. To avoid this, you will have to pass the list gotten from pygame.event.get() as an argument for the update function, and search through it for a MOUSEBUTTONDOWN event, but this would cause unnecessary complications that I tried to avoid.
The main code:
rectOn=False
while True:
if rectOn:
if rect.update()=='closed':
rectOn=False
To make the rect appear again after it has been closed, simply set rectOn to True.
A made a small example that you can work on. Instead of buttons returning something on click, they have a function assigned to the click.
import pygame,sys
from pygame.locals import *
screen_color = (0,0,0)
class Button:
def __init__(self,pos,action):
self.rect = pygame.Rect(pos)
self.action = action
def draw(self,screen):
pygame.draw.rect(screen, (255,255,255), self.rect)
def checkCollide(self,x,y):
return self.rect.collidepoint(x,y)
def do(self):
self.action()
def action():
global screen_color
screen_color = (255,255,0)
pygame.init()
screen = pygame.display.set_mode((640,360),0,32)
buttons = []
buttons.append(Button((10,10,50,50),action))
while True:
screen.fill(screen_color)
for button in buttons:
button.draw(screen)
pygame.display.flip()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
x,y = pygame.mouse.get_pos()
for button in buttons:
if (button.checkCollide(x,y)):
button.do()

Categories