无法将一次鼠标单击转换为多次鼠标单击。基本上,我想做的是同时控制多个窗口。我想点击一个主窗口,并让点击传播到后续窗口。在这个片段中,有4个窗口,我通过确定它和主窗口之间的offset
来跟踪它们。
我使用python3和pynput作为鼠标侦听器,使用pyautogui进行鼠标控制。
我遇到的问题是设置鼠标侦听器,使其侦听我的实际点击,但忽略程序化的点击。现在,我认为它陷入了一个无限循环,我的第一次点击触发了on_click
事件,传播点击,每次触发一个额外的on_click
事件,传播单击,等等。当我运行下面的代码时,它开始得很好,然后当我第一次点击时,它只是严重滞后了我的鼠标一分钟,然后恢复正常,不再有鼠标侦听器活动。我的猜测是,一个故障保险会启动,使其恢复正常。
我尝试过的东西:
- 使用pynput进行侦听器和控制-这不会改变结果
- 在传播的点击完成后停止侦听器并创建一个新的侦听器-糟糕的破解解决方案仍然没有改变结果
- 如果信号量已经被获取,则使用
_value
窥视来忽略事件的信号量锁定-也很糟糕,不起作用 - 通过线程调用
propagateActions
并在从on_click
事件返回之前等待完成-不起作用 - 注释掉
pyautogui.click()
-这允许预期的行为将鼠标移动到后续位置,然后将其返回到初始位置。没有点击,它工作得很完美。随着点击,它会滞后,侦听器也会死亡 - 搜索stackoverflow-这个问题在结果上有相似之处,但没有答案,并且正在努力实现不同的目标
我的代码片段如下:
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()
我的问题:
- 有没有办法只听";真实的";点击而不是编程点击
- 如果没有,我可以暂停鼠标侦听器,然后在传播的单击发生后以某种方式重新启动它吗
这是与当前问题相关的一小段代码。offsets
有一个更合适的初始化设置,还有其他的提示,但这是与问题相关的部分。我感谢你的帮助。
找到了答案!不得不更深入一层。
Pynput有一种抑制事件的方法,该方法在单击事件后面公开win32数据。对我的一次点击与pyautogui.click()
进行了测试,结果发现有区别。在用户点击事件中将data.flags
设置为值0
,在编程点击事件中将其设置为值1
。
这对我来说已经足够好了。这是相关的过滤器:
def win32_event_filter(msg, data):
if data.flags:
print('suppressing event')
return False
将其添加到我的上述代码中,并更改了
mouseListener = mouse.Listener(on_click=on_click)
至
mouseListener = mouse.Listener(on_click=on_click, win32_event_filter=win32_event_filter)
它起作用了!
我真正的点击占了上风,程序化的点击被传播,我没有陷入无限循环。如果其他人遇到这个问题,希望这能有所帮助。