Using pynput to get mouse coordinates - python

The program runs, but onclick I do not get a print statement of my x, and y.
I built a simple MoustInput class like so
from pynput import mouse
class MouseInput:
def __init__(self):
with mouse.Listener(on_click=self.on_click) as listener:
listener.join()
def on_click(self, x, y, button, pressed):
print('{0} at {1}'.format(
'Pressed' if pressed else 'Released',
(x, y)))
if not pressed:
# Stop listener
return False
and then in app.py
I have something like this to call the class
from MouseInputs.mouse_input import MouseInput
if __name__ == "__main__":
MouseInput()

Fixed the issue.. It was a Mac related problem not allowing inputs to be detected..
I fixed this by allowing VSCode, and the terminal in accessibility in the Security & Privacy section of system preferences.

Related

PYTHON | Apps Unable to Take Automated Mouse Input

Recently after upgrading to Windows 11, I've found that some apps can't receive automated mouse and keyboard actions. The script simply goes to a location and clicks but after going to the location, the program doesn't respond to the clicks. Further more, the mouse cursor doesn't change to indicated that the element is clickable. I've tried several methods already, PyDirectInput, Pynput and Pyautogui.
I'm running the script to the application Roblox and I'm using Pycharm as an IDE.
Script with pydirectinput:
import pydirectinput
import pyautogui
import time
x, y = pyautogui.size()
def click_ratio(xr, yr):
global x, y
pydirectinput.click(int(x/xr), int(y/yr))
pyautogui.alert()
time.sleep(1)
click_ratio(1.057414291615035, 1.6881594372801876)
Script with pynput:
from pynput.mouse import Button, Controller
import pyautogui
import time
x, y = pyautogui.size()
mouse = Controller()
def click_ratio(xr, yr):
global x, y
mouse.position((int(x/xr), int(y/yr)))
mouse.click(Button.left, 2)
pyautogui.alert()
time.sleep(1)
click_ratio(1.057414291615035, 1.6881594372801876)
Script using pyautogui:
import pyautogui
import time
x, y = pyautogui.size()
def click_ratio(xr, yr):
global x, y
pyautogui.click((int(x/xr), int(y/yr)))
pyautogui.alert()
time.sleep(1)
click_ratio(1.057414291615035, 1.6881594372801876)
The clicking works fine on Chrome. If anyone could help me, it would be greatly appreciated.

Why do I always have the error message Controller has no attribute is_pressed?

I've been coding a very simple autoclicker. My autoclicker works just fine, but the only way to kill it is forcefully shut down my computer because it clicks so fast I can't access my taskbar. I could make it slower, but I'd prefer a way for the user to close the autoclicker with the press of a button. I've tried if keyboard.is_presssed('q'): break but I always get the error message AttributeError: 'Controller' object has no attribute 'is_pressed'. Did you mean: 'alt_pressed'? I expected my code to break the loop when I press q, but instead I get an error message. The error message will also pop up without the pressing of q. My code as of now is:
from pynput.mouse import Button, Controller
from pynput.keyboard import Key, Controller
import time
keyboard = Controller()
mouse = Controller()
while True:
time.sleep(10)
mouse.click(Button.left)
if keyboard.is_pressed('q'):
break
pynput doesn't have is_pressed() - I don't know where you find it.
You should rather use pynput.keyboard.Listener to run code when q is pressed and set some variable - q_is_pressed = True - or run code which ends program.
You can't have two objects with the same name Controller.
One Controller replaces other Controller and later you use the same Controller to create mouse and keyboard - and this makes problem.
You have to use pynput.mouse.Controller and pynput.keyboard.pynput.Controller
import pynput
from pynput.mouse import Button
from pynput.keyboard import Key
import time
keyboard = pynput.keyboard.Controller()
mouse = pynput.mouse.Controller()
while True:
time.sleep(10)
mouse.click(Button.left)
#if keyboard.is_pressed('q'): # <-- this will need Listener()
# break
EDIT:
To end code when q was pressed you have to use Listener
For example:
import pynput
from pynput.mouse import Button
import time
mouse_controller = pynput.mouse.Controller()
def on_press(key):
print('pressed:', key)
if str(key) == "'q'": # it has to be with `' '` inside `" "`
# Stop listener
print("exit listener")
return False # `False` ends listener
with pynput.keyboard.Listener(on_press=on_press) as keyboard_listener:
while keyboard_listener.is_alive():
time.sleep(10)
mouse_controller.click(Button.left)
print('clicked')

Python Global Capturing and Disposing Mouse Click Event

I want to create a tool, which allows me to send keys to active window using my mouse.
Let's say I want to send the key "A" when I click the left mouse button. But I also want to suppress / dispose that particular click event. So the target app will only feel the keyboard input "A", but not the left click of the mouse event.
With the following code I am able to see the mouse clicks. But I want to dispose / stop the event and not processed by the system.
from pynput import mouse
def do_something():
print("something")
def on_click(x, y, button, pressed):
print('{0} {1} at {2}'.format(button, 'Pressed' if pressed else 'Released', (x, y)))
if (button.value == 1):
do_something()
#suppress / dispose the click event...
# Collect events until released
with mouse.Listener( on_click=on_click ) as listener:
listener.join()
By the way I am using Ubuntu 20.04.
Thanks in advance.
I found a way that suppress all the click events.
from pynput import mouse
def do_something():
print("something")
def on_click(x, y, button, pressed):
print('{0} {1} at {2}'.format(button, 'Pressed' if pressed else 'Released', (x, y)))
if (button.value == 1):
do_something()
#suppress / dispose the click event...
# Collect events until released
with mouse.Listener( on_click=on_click, suppress=True ) as listener:
listener.join()
I am still looking for a solution to suppress a certain button click.

Disable keyboard but keep getting events

I have a touchscreen laptop that folds back enough to become like a tablet. If I put it down on the table, I don't want to be hitting keys accidentally, so I'm working on a script to disable the keyboard when I hit Ctrl-F10 and then re-enable it when I do that again. I'm using xlib from PyPI, and I've gotten this so far:
from Xlib.display import Display
from Xlib.ext import xinput
class Handler:
def __init__(self, display):
self.enabled = True
self.display = display
def handle(self, event):
if event.data['detail'] == 76 and event.data['mods']['base_mods'] == 4:
if self.enabled:
self.display.grab_server()
else:
self.display.ungrab_server()
self.enabled = not self.enabled
try:
display = Display()
handler = Handler(display)
screen = display.screen()
screen.root.xinput_select_events([
(xinput.AllDevices, xinput.KeyPressMask),
])
while True:
event = display.next_event()
handler.handle(event)
finally:
display.close()
It does disable the keyboard on Ctrl-F10, but as soon as I re-enable, all the keys I pressed when it was disabled are activated all at once. Is there a way to clear the queue before re-enabling, or a better way to disable the keyboard?
Try XGrabKeyboard: https://tronche.com/gui/x/xlib/input/XGrabKeyboard.html
(But this requires you to create your own window for grabbing; you can e.g. create a window of size 1x1 at position -10x-10)
I think the values for things like owner_events and keyboard_mode do not matter much. The main effect should be that the input focus goes to your own window. time should be CurrentTime (which is 0) and pointer_mode should be GrabModeAsync, so that you do not interfere with the pointer.

How do I bind an event to the left mouse button being held down?

I need a command to be executed as long as the left mouse button is being held down.
If you want "something to happen" without any intervening events (ie: without the user moving the mouse or pressing any other buttons) your only choice is to poll. Set a flag when the button is pressed, unset it when released. While polling, check the flag and run your code if its set.
Here's something to illustrate the point:
import Tkinter
class App:
def __init__(self, root):
self.root = root
self.mouse_pressed = False
f = Tkinter.Frame(width=100, height=100, background="bisque")
f.pack(padx=100, pady=100)
f.bind("<ButtonPress-1>", self.OnMouseDown)
f.bind("<ButtonRelease-1>", self.OnMouseUp)
def do_work(self):
x = self.root.winfo_pointerx()
y = self.root.winfo_pointery()
print "button is being pressed... %s/%s" % (x, y)
def OnMouseDown(self, event):
self.mouse_pressed = True
self.poll()
def OnMouseUp(self, event):
self.root.after_cancel(self.after_id)
def poll(self):
if self.mouse_pressed:
self.do_work()
self.after_id = self.root.after(250, self.poll)
root=Tkinter.Tk()
app = App(root)
root.mainloop()
However, polling is generally not necessary in a GUI app. You probably only care about what happens while the mouse is pressed and is moving. In that case, instead of the poll function simply bind do_work to a <B1-Motion> event.
Look at table 7-1 of the docs. There are events that specify motion while the button is pressed, <B1-Motion>, <B2-Motion> etc.
If you're not talking about a press-and-move event, then you can start doing your activity on <Button-1> and stop doing it when you receive <B1-Release>.
Use the mouse move/motion events and check the modifier flags. The mouse buttons will show up there.

Categories