Python 3.x - Multi mouse button activated auto clicker - python-3.x

I am having troubles with the python code i am trying to write. I am attempting to create an auto-clicker that when I hold down left click and one of the side buttons, left click gets triggered every 0.1 seconds. If I let go of either button, the auto-clicker stops. I have searched through the PyAutoGUI, PyNput, and the PyGame libraries, as well as many of stack overflow posts on the topic of mouse detection. Here is the code I have put together so far. (note, a majority of this code is not mine, I simply do not remember where I grabbed the code snippits otherwise they would be linked below.
from pynput import mouse
from pynput.mouse import Button, Controller
import threading
import time
control = Controller()
running = False
leftPressed=False
rightPressed=False
def process():
print('start')
count = 0
while running:
print(count)
count += 1
control.click(Button.left,1)
print("test")
time.sleep(.05)
print('stop')
def on_click(*args):
global running, leftPressed, rightPressed
if args[-1]:
# mouse key pressed
if args[-2].name == "left":
leftPressed = True
print("Left click")
elif args[-2].name == "x2":
rightPressed = True
if leftPressed and rightPressed:
# if both left and right are pressed
running = True
threading.Thread(target=process).start()
elif not args[-1]:
# mouse key released
if args[-2].name == "x1":
leftPressed = False
elif args[-2].name == "x2":
rightPressed = False
# as one key has been released, both are no longer pressed
running = False
with mouse.Listener(on_click=on_click) as listener:
listener.join()
Any help with this project would be greatly appreciated, I've come to realize the biggest issue is that since the "on click" event is expecting a left click to run the thread, left clicking inside of the thread is more than not ideal, however if it is possible to program it in such a way where this isn't an issue it would be greatly appreciated.
The pseudocode for what I am looking for would be:
if Button.x2 == pressed and Button.left == pressed:
bothPressed = True
else:
bothPressed = False
while bothPressed:
Button.left.click()
I have tried using multiple methods of obtaining the mouse inputs through PyGame and PyNput. However I've found that I understand PyNput the best and would prefer to stick with it.

Related

pywin.dialogs.list.ListDialog: Unexpected focus when called after global hot key pressed

Sorry for the weird title. I don't know how else to phrase it. Please feel free to re-write/improve the title with edits.
Using Python 3 on Win 10, this code works well to pop-up a small MFC dialog with a selection box:
import pywin.dialogs.list
if __name__ == "__main__":
pywin.dialogs.list.ListDialog("Window Title", ["abc", "def"]).DoModal()
When I run this code, the dialog takes focus and is the activated window.
Next, I would like to trigger this dialog from a global hot key: Ctrl+Alt+Shift+P
import ctypes.wintypes
from ctypes import windll
import pywin.dialogs.list
import win32con
if __name__ == "__main__":
hot_key_index = 0
if not ctypes.windll.user32.RegisterHotKey(None, hot_key_index, win32con.MOD_ALT + win32con.MOD_CONTROL + win32con.MOD_SHIFT, ord('P')):
raise Exception("Failed: user32.RegisterHotKey()")
try:
msg = ctypes.wintypes.MSG()
while windll.user32.GetMessageA(ctypes.byref(msg), None, 0, 0) != 0:
if msg.message == win32con.WM_HOTKEY:
if hot_key_index == msg.wParam:
pywin.dialogs.list.ListDialog("Window Title", ["abc", "def"]).DoModal()
windll.user32.TranslateMessage(ctypes.byref(msg))
windll.user32.DispatchMessageA(ctypes.byref(msg))
finally:
windll.user32.UnregisterHotKey(None, hot_key_index)
Run the code, then strike: Ctrl+Alt+Shift+P. The global hot key dialog will pop-up... or rather pop-under. I always need to do Alt+Tab to find the dialog. It does not take focus and is not the activated window.
I tried to find different ways set focus. However, I cannot find a working solution. Example that does not work:
hWnd = dlg._obj_.GetSafeHwnd()
win32gui.SetFocus(hWnd)
By luck, I discovered if I display a dummy message box before starting the message loop, the global hot key pop-up dialog takes focus correctly.
This works, but why? (It feels like a strange MFC init issue, but this is beyond my area of expertise.)
if __name__ == "__main__":
win32api.MessageBox(None, "message", "title", win32con.MB_OK)
hot_key_index = 0
...

popup in tkinter with pygame that doest go away unless closed/pressed ok

I am trying to get a popup for my pygame screen using tkinter, but i just want a simple messagebox that i pass in the message, and message type (like: "error"). What i don't know how to do is make it so that they can't avoid not answering it, if they click somewhere else it will not let the user do anything till they answer it, not even go to desktop sort of thing.
what i have so far:
def popUp(self, message, messagetype='Error'):
#Tk().wm_withdraw() #to hide the main window
messagebox.showinfo(messagetype, message)
For this to work your games's mainloop must be in a function (let's call it play). Let's say you have very simple code.
When a condition is met you can access the new function popUp. Which can have your tkinter window. When the button is pressed you can have its command as ...command=play) if the player wants to restart. As the popUp function is not inside the mainloop the game will be unresponsive. An example:
def play():
while carryOn:
for event in pygame.event.get():
if event.type==pygame.QUIT:
carryOn=False
#Checking if a key is pressed and then responding e=with function in the sprite class
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.moveLeft(5)
if keys[pygame.K_RIGHT]:
player.moveRight(5)
if keys[pygame.K_UP]:
player.moveUp(5)
if keys[pygame.K_DOWN]:
player.moveDown(5)
if keys[pygame.K_a]:
player.moveLeft(5)
if keys[pygame.K_d]:
player.moveRight(5)
if keys[pygame.K_w]:
player.moveUp(5)
if keys[pygame.K_s]:
player.moveDown(5)
#yourcondition
# if ... :
# carryOn = False
# popUp()
#Game Logic
all_sprites_list.update()
#Setting the background
screen.fill(GREEN)
#Now let's draw all the sprites
all_sprites_list.draw(screen)
#Refresh Screen
pygame.display.flip()
#Number of frames per second
clock.tick(60)
This is not full code - missing sprite class and code before that. You could then have your tkinter window (after importing tkinter) like:
global window #so it can be destroyed in the other function
window = Tk()
#message = ...
#message.grid ...
button = Button(window, text="restart", width=5, command=play)
button.grid # where you want it
The game will be frozen until the user presses restart (you may also want a window .destroy() in your code somewhere. You can adapt this to pretty much whatever you want but it is no where close to complete code. I hope this was useful.

how do I let my program know and respond to a key being pressed

I am thirteen years old, and I am learning to code. I think that I am doing quite well, however, I have hit a massive roadblock.
I am trying to program some sort of advanced Etch a sketch game, and with the general coding, I can do it.
like:
if the player says 'forward' + number:
go forward by that number.
that all works and it can draw shapes and everything, and rub out and change color even.
But what I am trying to do, is make my program respond to going forward when the button 'w' 'a' 's' or 'd' buttons are pressed, then without clicking enter, have it immediately have a turtle move by 40 pixels up, down, left or right.
I am using a platform called Trinket.io and so far it is proving very useful to code on. but whenever I find a website that says, 'this should work!' it doesn't. or it is only a snippet of code, or whatever the problem is, the program won't respond when I click w a s or d.
On Trinket.io, when you open up a pygame trinket it gives you two example games that both work on w a s d movement. I have tried to take some code form that, and modify it so it will print some text 'you clicked a' or 'you clicked w'. This hasn't worked either.
By the way, all of this testing has been done on a completely different trinket so various bits of code in the Etch a sketch prodject can't be the problem.
from time import *
import pygame
pygame.init()
UP = 'up'
DOWN = 'down'
LEFT = 'left'
RIGHT = 'right'
while True: # main game loop
for event in pygame.event.get(): # event handling loop
if event.type == K_DOWN:
print('key down')
elif event.key == K_UP:
print('key up')
this piece of code is as close as I think I have gotten so far to my goal as it produces no error messages, it just doesn't work or do anything.
Try putting your event handling loop in a different thread so it can run with your game:
from time import *
import pygame
import _thread
pygame.init()
UP = 'up'
DOWN = 'down'
LEFT = 'left'
RIGHT = 'right'
def controller():
while True: # main game loop
for event in pygame.event.get(): # event handling loop
if event.type == K_DOWN:
print('key down')
elif event.key == K_UP:
print('key up')
_thread.start_new_thread(controller)
Your controller should be running parallel with your game, This means that the rest of your game will also have to be put into it's own thread
.
See this for more info on threading: https://www.tutorialspoint.com/python3/python_multithreading.htm

Why does tkinter sometimes work without mainloop in Python 3?

Here's code for a little game. You're supposed to hit buttons that say 'click' to score points and avoid hitting buttons that say 'clack' or 'cluck' which cause you to lose points. The first weird thing is that the program works fine under IDLE even though it doesn't include a call to mainloop. The second is that it stops working if we add the following line at the bottom:
input('Hit enter to continue')
No game window appears, even after we hit enter. Adding a different line at the end like
print('hello')
does not have this effect.
Can anyone explain to me what's going on? I know that GUI programs used to run under IDLE's own mainloop, but that was a long time ago in Python 2 and definitely wasn't generally true under Python 3, at least last time I checked.
from tkinter import *
import random
score = 0
root = Tk()
scoreFrame = Frame(root)
scoreFrame.pack(expand = YES, fill = BOTH)
scoreLabel = Label(scoreFrame)
scoreLabel.pack()
def showScore():
scoreLabel['text'] = 'Score: {0}'.format(score)
scoreLabel.pack()
clickFrame = Frame(root)
clickFrame.pack(side = BOTTOM, expand = YES, fill = BOTH)
def changeLabels():
for button in buttons:
button['text'] = random.choice(['click', 'clack', 'cluck'])
button['bg'] = buttonDefaultColor
root.after(1500, changeLabels)
def makeButton():
button = Button(clickFrame)
def cmd():
global score
if button['bg'] == buttonDefaultColor:
if button['text'] == 'click':
score += 10
button['bg'] = 'light green'
else:
score -= 10
button['bg'] = 'light yellow'
button['command'] = cmd
button.pack(side = LEFT, expand = YES, fill = BOTH)
return button
buttons = [makeButton() for i in range(5)]
buttonDefaultColor = buttons[0]['bg']
changeLabels()
showScore()
Added: The first three comments all suggest that IDLE is running the event loop for me, making mainloop unnecessary but (1) I remember clearly when this suddenly stopped being true some years back (not that IDLE stopped running mainloop, but that GUI programs running under it did not need to run mainloop themselves) and (2) no one has explained why the input statement at the end breaks the program.

Stopping, restarting and changing variables in a thread from the main program (Python 3.5)

I'm very new to threading am and still trying to get my head around how to code most of it. I am trying to make what is effectively a text editor-type input box and so, like every text editor I know, I need a cursor-bar thing to indicate the location at which the text is being typed to. Thus I also want to be able to flicker/blink the cursor, which i thought would also prove good practice for threading.
I have a class cursor that creates a rectangle on the canvas based on the bounding box of my canvas text, but I then need to change it's location as more characters are typed; stop the thread and instantaneously hide the cursor rectangle when the user clicks outside of the input box; and lastly restart the thread/a loop within the thread (once again, sharing a variable) - the idea here being that the cursor blinks 250 times and after then, disappears (though not necessary, I thought it would make a good learning exercise).
So assuming that I have captured the events needed to trigger these, what would be the best way to go about them? I have some code, but I really don't think it will work, and just keeps getting messier. My idea being that the blinking method itself was the thread. Would it be better to make the whole class a thread instead? Please don't feel restricted by the ideas in my code and feel free to improve it. I don't think that the stopping is working correctly because every time I alt+tab out of the window (which i have programmed to disengage from the input box) the Python shell and tkinter GUI stop responding.
from tkinter import *
import threading, time
class Cursor:
def __init__(self, parent, xy):
self.parent = parent
#xy is a tuple of 4 integers based on a text object's .bbox()
coords = [xy[2]] + list(xy[1:])
self.obj = self.parent.create_rectangle(coords)
self.parent.itemconfig(self.obj, state='hidden')
def blink(self):
blinks = 0
while not self.stop blinks <= 250:
self.parent.itemconfig(self.obj, state='normal')
for i in range(8):
time.sleep(0.1)
if self.stop: break
self.parent.itemconfig(self.obj, state='hidden')
time.sleep(0.2)
blinks += 1
self.parent.itemconfig(self.obj, state='hidden')
def startThread(self):
self.stop = False
self.blinking = threading.Thread(target=self.blink, args=[])
self.blinking.start()
def stopThread(self):
self.stop = True
self.blinking.join()
def adjustPos(self, xy):
#I am not overly sure if this will work because of the thread...
coords = [xy[2]] + list(xy[1:])
self.parent.coords(self.obj, coords)
#Below this comment, I have extracted relevant parts of classes to global
#and therefore, it may not be completely syntactically correct nor
#specifically how I initially wrote the code.
def keyPress(e):
text = canvas.itemcget(textObj, text)
if focused:
if '\\x' not in repr(e.char) and len(e.char)>0:
text += e.char
elif e.keysym == 'BackSpace':
text = text[:-1]
canvas.itemconfig(textObj, text=text)
cursor.adjustPos(canvas.bbox(textObj))
def toggle(e):
if cursor.blinking.isAlive(): #<< I'm not sure if that is right?
cursor.stopThread()
else:
cursor.startThread()
if __name__=="__main__":
root = Tk()
canvas = Canvas(root, width=600, height=400, borderwidth=0, hightlightthickness=0)
canvas.pack()
textObj = canvas.create_text(50, 50, text='', anchor=NW)
root.bind('<Key>', keyPress)
cursor = Cursor(canvas, canvas.bbox(textObj))
#Using left-click event to toggle thread start and stop
root.bind('<ButtonPress-1', toggle)
#Using right-click event to somehow restart thread or set blinks=0
#root.bind('<ButtonPress-3', cursor.dosomething_butimnotsurewhat)
root.mainloop()
If there is a better way to do something written above, please also tell me.
Thanks.

Resources