Pynput check if key is currently being pressed - python

I'm writing a background scrypt that requires a left mouse button to be pressed. Currently my code looks something like this:
from pynput.mouse import Button
from pynput.mouse import Controller
mouse = Controller()
def main():
mouse.press(Button.left)
while True:
#do sth every n seconds
main()
However, background activity sometimes causes the mouse button to be released.
Is there a way to check if the key is pressed within the while loop (Something like mouse.is_pressed(Button.left)) other than adding another mouse.press(pynput.mouse.Button.left) every iteration of loop?

Related

Problem with keyboard library, exactly with stopping .record() in function

import keyboard
import time
import pyautogui
import mouse
def call_record():
event = keyboard.record(until='shift')
print("ended record")
def call_playrecord():
print('playing...')
keyboard.play(event)
keyboard.add_hotkey('l', call_record)
keyboard.add_hotkey('n+m', call_playrecord)
keyboard.wait('esc')
This is a code and a problem about that, is that record wont stop when i press 'shift'
(nevermind that i dont have global set on event i will make this later)
I tried to make a record and play system with hotkeys but i cant stop the record

How to make the Keyboard module detect if a right click was made

I have tried to search google and other websites such as GitHub but I cant find a way to detect if the right key has been pressed. I am using the two modules Keyboard and Pyautogui to make a auto clicker but all the ideas that I have come up with have failed. Here is my code:
import keyboard
import pyautogui
pyautogui.PAUSE = 0.1
while True:
if keyboard.is_pressed('h'):
pyautogui.rightClick()
if keyboard.is_pressed('g'):
pyautogui.click()
I want a way to replace the h and g with right click and left click any ideas?
If you are trying to check for just mouse clicks, the pynput library could work.
from pynput import mouse
# mouse.Events looks at all events, you could use
# events = mouse.Events().get(1) to look at just the events in the last second
with mouse.Events() as events:
for event in events:
if isinstance(event, mouse.Events.Click):
if event.button == mouse.Button.right and event.pressed:
#Do stuff for right click
else:
print('Received event {}'.format(event))
I am using Click so that movements are not tracked. Similarly, press down/up are counted as separate events, so to filter those out using event.pressed
Take a look at https://pynput.readthedocs.io/en/latest/mouse.html for other mouse listener ideas

Taking Single Click Event and Propagating it to Multiple Areas - python, pynput, pyautogui

Having trouble turning 1 mouse click into multiple mouse clicks. Basically what I want to do is to control multiple windows at once. I want to click on one master window and have the clicks propagate to the subsequent windows. In this snippet there are 4 windows and I track them via determining the offset between it and the master window.
I'm using python3 with pynput for the mouse listener and pyautogui for mouse control.
What I'm having a problem with is setting up the mouse listener such that it listens to my actual clicks but ignores the programmatic clicks. Right now, I think it's getting stuck in an infinite loop where my initial click triggers the on_click event, propagates the clicks, each triggering an additional on_click event, propagates the clicks, etc. When I run the below code it starts fine, and then when I first click it just heavily lags my mouse for a minute before return back to normal with no mouse listener active anymore. My guess is that a failsafe kicks in to return it to normal.
Things I have tried:
using pynput for listener and control - this does not change the outcome
stopping the listener and creating a new one after propagated clicks have finished - bad hacky solution that still did not change the outcome
semaphore locking with _value peeking to ignore events if semaphore has already been acquired - also hacky and did not work
calling propagateActions via threading and waiting for completion before returning from on_click event - did not work
commenting out pyautogui.click() - this allows for expected behavior to move the mouse to the subsequent locations and return it back to its initial position after. Without the click, it works perfect. With the click, it lags and the listener dies.
searching stackoverflow - this question bears a resemblance in terms of outcome, but is unanswered and is trying to achieve something different.
My snippet is below:
from pynput import mouse, keyboard
import pyautogui
pyautogui.PAUSE = 0.01
mouseListener = None
killSwitch = False
# this is just a keyboard listener for a kill switch
def on_release(key):
if key == keyboard.Key.f1:
global killSwitch
print('### Kill switch activated ###')
killSwitch = True
# on mouse release I want to propogate a click to 4 other areas
def on_click(x, y, button, pressed):
print('{0} at {1}'.format('Pressed' if pressed else 'Released', (x, y)))
if not pressed:
propogateActions(x, y, button)
# propogates clicks
def propogateActions(x, y, button):
print('propogating actions to {0} windows'.format(len(offsets)+1))
for offset in offsets:
pyautogui.moveTo(x+offset.x, y+offset.y)
print('mouse moved')
if button == mouse.Button.left:
print('left clicking at ({0}, {1})'.format(x+offset.x, y+offset.y))
pyautogui.click()
pyautogui.moveTo(x, y)
# point class for ease of use
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return 'Point(x={0}, y={1})'.format(self.x, self.y)
# main method
def doTheThing():
print('started')
while not killSwitch:
pass
# initializations and starting listeners
# offsets tracks how far the subsequent clicks are from the initial click point
offsets = [Point(50, 0), Point(50, 50), Point(0, 50)]
keyboardListener = keyboard.Listener(on_release=on_release)
mouseListener = mouse.Listener(on_click=on_click)
keyboardListener.start()
mouseListener.start()
doTheThing()
My Question:
Is there some way to listen only for "real" clicks and not programmatic clicks?
If not, can I pause the mouse listener and then restart it some way after the propagated clicks have occurred?
This is the small section of code that's relevant to the issue at hand. offsets has an initialization that sets it more appropriately and there's other bells and whistles, but this is the section relevant to the problem. I appreciate your help.
Found the answer! Had to go a layer deeper.
Pynput has a method of suppressing events that exposes the win32 data behind the click event. Ran a test of one of my clicks vs a pyautogui.click() and lo-and-behold there is a difference. The data.flags was set to value 0 on a user click event and set to value 1 on a programmatic click.
That's good enough for me to filter on. This is the pertinent filter:
def win32_event_filter(msg, data):
if data.flags:
print('suppressing event')
return False
added that to my above code and changed the
mouseListener = mouse.Listener(on_click=on_click)
to
mouseListener = mouse.Listener(on_click=on_click, win32_event_filter=win32_event_filter)
and it works!
My real clicks prevail, programmatic clicks are propagated, and I am not stuck in an infinite loop. Hope this helps if others run into this issue.

How to make python play a mouse events recording only WHILE left key is pressed?

I'm new to python and I'm trying to learn how to use the mouse and keyboard modules. I am trying to write some code that plays a recording while I'm holding left click, I think the issue is that this may be only part of the recording depending on how long I hold it. This is what I have so far but it isn't playing the recording.
import mouse
import keyboard
events = [] #This is the list where all the events will be stored
mouse.hook(events.append) #starting the recording
keyboard.wait("a") #Waiting for 'a' to be pressed
mouse.unhook(events.append) #Stopping the recording
def onleftclick():
while mouse.is_pressed(button='left') == True:
mouse.play(events)
mouse.on_click(onleftclick)
keyboard.wait('esc')
you could do:
import keyboard
while True:
#lets just say that you want to detect q and left key pressed
if keyboard.is_pressed('left') and keyboard.is_pressed('q'):
print('left key and q pressed')
Use a keystroke to play back the recording. The recording won't play if you're using the mouse.
Try this code. Press a to play back the recording:
import mouse
import keyboard
events = [] #This is the list where all the events will be stored
mouse.hook(events.append) #starting the recording
keyboard.wait("a") #Waiting for 'a' to be pressed
print('playback...')
mouse.unhook(events.append) #Stopping the recording
mouse.play(events)
keyboard.wait('esc')
print('bye')

Double click when clicking once pynput

Trying to do a program that double clicks for you when you click the left mouse button once with pynput. I have the following code, but if I run the code, my mouse glitches out and stops working.
from pynput.mouse import Listener, Button, Controller
mouse = Controller()
def on_click(x, y, button, pressed):
if pressed == True:
mouse.click(Button.left, 2)
else:
pass
with Listener(on_click=on_click) as listener:
listener.join()
Also in addition of this, how would the implementation of pressing "F10" enables that 1 click acts like double click and pressing "F10" again would disable it, so 1 click would act like 1 click be possible?
Oh,I maybe find your problem,
Two probable causes:
In your script,when your press the mouse button.It will call function on_click.Then it will mouse.click(Button.left, 2).But this code will also call on_click.So it will be a endless loop.Finally,you will find your mouse will be not responding.So I think you should use another way to do that.
In pynput official document,It seems it can be used in macOS(maybe windows couldn't use it.And I also found if I only use mouse.click(Button.left, 2) in my PC,my python will be not responding.(It couldn't be stopped).Maybe you should just use .press and .release directly):
Also in addition of this, how would the implementation of pressing "F10" enables that 1 click acts like double click and pressing "F10" again would disable it.
So this seems a switch,you can use a global variable to do that.There is a minimal example of use pynput to do a switch.(This will don't print Mode is on if you don't press F10,and it won't print it after you press F10 again).
# import win32api,win32con
from pynput.mouse import Controller
from pynput import keyboard
from pynput.keyboard import Key
mouse = Controller()
Mode = False
def on_press(key):
global Mode
if key == Key.f10:
if Mode:
Mode = False
else:
Mode = True
listener = keyboard.Listener(on_press=on_press)
listener.start()
while True:
if Mode:
print("Mode is on")

Categories