之前看了水哥的自动化视频,觉得非常牛逼,准备自己上手写点自动化的东西,但奈何pyautogui最后一次更新的时间是Jul 8, 2021,这就很尴尬了,现在mac的版本都12,13了,虽然大部分的功能都能适配,但是仍然存在某些小问题。
import pyautogui
pyautogui.doubleClick(1324,315)
正常的双击,我们可以发现,他无法打开文件
def doubleClick(x=None, y=None, interval=0.0, button=LEFT, duration=0.0, tween=linear, logScreenshot=None, _pause=True):
if sys.platform == "darwin":
x, y = _normalizeXYArgs(x, y)
_mouseMoveDrag("move", x, y, 0, 0, duration=0, tween=None)
x, y = platformModule._position()
platformModule._multiClick(x, y, button, 2)
_logScreenshot(logScreenshot, 'click', '%s,2,%s,%s' % (button, x, y), folder='.')
else:
# Click for Windows or Linux:
click(x, y, 2, interval, button, duration, tween, logScreenshot, _pause=False)
def _multiClick(x, y, button, num, interval=0.0):
btn = None
down = None
up = None
if button == LEFT:
btn = Quartz.kCGMouseButtonLeft
down = Quartz.kCGEventLeftMouseDown
up = Quartz.kCGEventLeftMouseUp
elif button == MIDDLE:
btn = Quartz.kCGMouseButtonCenter
down = Quartz.kCGEventOtherMouseDown
up = Quartz.kCGEventOtherMouseUp
elif button == RIGHT:
btn = Quartz.kCGMouseButtonRight
down = Quartz.kCGEventRightMouseDown
up = Quartz.kCGEventRightMouseUp
else:
assert False, "button argument not in ('left', 'middle', 'right')"
return
for i in range(num):
_click(x, y, button)
time.sleep(interval)
def _click(x, y, button):
if button == LEFT:
_sendMouseEvent(Quartz.kCGEventLeftMouseDown, x, y, Quartz.kCGMouseButtonLeft)
_sendMouseEvent(Quartz.kCGEventLeftMouseUp, x, y, Quartz.kCGMouseButtonLeft)
elif button == MIDDLE:
_sendMouseEvent(Quartz.kCGEventOtherMouseDown, x, y, Quartz.kCGMouseButtonCenter)
_sendMouseEvent(Quartz.kCGEventOtherMouseUp, x, y, Quartz.kCGMouseButtonCenter)
elif button == RIGHT:
_sendMouseEvent(Quartz.kCGEventRightMouseDown, x, y, Quartz.kCGMouseButtonRight)
_sendMouseEvent(Quartz.kCGEventRightMouseUp, x, y, Quartz.kCGMouseButtonRight)
else:
assert False, "button argument not in ('left', 'middle', 'right')"
通过查看源码,我们可以发现,作为darwin的mac他调用双击的事件与正常pyobjc提供的双击事件不同。
from Quartz.CoreGraphics import *
def mouseDoubleClick(posx, posy):
'''perfrom a double left click'''
theEvent = CGEventCreateMouseEvent(None, kCGEventLeftMouseDown, (posx, posy), kCGMouseButtonLeft);
CGEventPost(kCGHIDEventTap, theEvent);
CGEventSetType(theEvent, kCGEventLeftMouseUp);
CGEventPost(kCGHIDEventTap, theEvent);
CGEventSetIntegerValueField(theEvent, kCGMouseEventClickState, 2);
CGEventSetType(theEvent, kCGEventLeftMouseDown);
CGEventPost(kCGHIDEventTap, theEvent);
CGEventSetType(theEvent, kCGEventLeftMouseUp);
CGEventPost(kCGHIDEventTap, theEvent);
通过比对发现,pyautogui缺少CGEventSetIntegerValueField这个函数,导致虽然完成双击事件,但无法双击打开文件
这里说一下,这个插件,比较好,是22年一直在维护的一个库,可以满足双击打开文件的需求
from pynput.mouse import Button, Controller as c_mouse
import sys
print(sys.platform)
mouse= c_mouse()
# mouse.move(1324,315)
mouse.position = (1324,315)
mousePosition=mouse.position
mouse.click(Button.left, 2)
我们也来看看他的源码
def click(self, button, count=1):
"""Emits a button click event at the current position.
The default implementation sends a series of press and release events.
:param Button button: The button to click.
:param int count: The number of clicks to send.
"""
with self as controller:
for _ in range(count):
controller.press(button)
controller.release(button)
def _press(self, button):
(press, _, _), mouse_button = button.value
event = Quartz.CGEventCreateMouseEvent(
None,
press,
self.position,
mouse_button)
# If we are performing a click, we need to set this state flag
if self._click is not None:
self._click += 1
Quartz.CGEventSetIntegerValueField(
event,
Quartz.kCGMouseEventClickState,
self._click)
Quartz.CGEventPost(Quartz.kCGHIDEventTap, event)
# Store the button to enable dragging
self._drag_button = button
def _release(self, button):
(_, release, _), mouse_button = button.value
event = Quartz.CGEventCreateMouseEvent(
None,
release,
self.position,
mouse_button)
# If we are performing a click, we need to set this state flag
if self._click is not None:
Quartz.CGEventSetIntegerValueField(
event,
Quartz.kCGMouseEventClickState,
self._click)
Quartz.CGEventPost(Quartz.kCGHIDEventTap, event)
if button == self._drag_button:
self._drag_button = None
通过对比我们发现,在这个库里面使用了CGEventSetIntegerValueField这个函数,可以完成任务。
可以用pynupt
from pynput.mouse import Button, Controller as c_mouse
mouse= c_mouse()
mouse.position = (1324,315)
mousePosition=mouse.position
mouse.click(Button.left, 2)
先改这个文件_pyautogui_osx.py
def _click(x, y, button, num):
if button == LEFT:
_sendMouseEvent_2(Quartz.kCGEventLeftMouseDown, x, y, Quartz.kCGMouseButtonLeft, num)
_sendMouseEvent_2(Quartz.kCGEventLeftMouseUp, x, y, Quartz.kCGMouseButtonLeft, num)
elif button == MIDDLE:
_sendMouseEvent_2(Quartz.kCGEventOtherMouseDown, x, y, Quartz.kCGMouseButtonCenter, num)
_sendMouseEvent_2(Quartz.kCGEventOtherMouseUp, x, y, Quartz.kCGMouseButtonCenter, num)
elif button == RIGHT:
_sendMouseEvent_2(Quartz.kCGEventRightMouseDown, x, y, Quartz.kCGMouseButtonRight, num)
_sendMouseEvent_2(Quartz.kCGEventRightMouseUp, x, y, Quartz.kCGMouseButtonRight, num)
else:
assert False, "button argument not in ('left', 'middle', 'right')"
def _multiClick(x, y, button, num, interval=0.0):
btn = None
down = None
up = None
if button == LEFT:
btn = Quartz.kCGMouseButtonLeft
down = Quartz.kCGEventLeftMouseDown
up = Quartz.kCGEventLeftMouseUp
elif button == MIDDLE:
btn = Quartz.kCGMouseButtonCenter
down = Quartz.kCGEventOtherMouseDown
up = Quartz.kCGEventOtherMouseUp
elif button == RIGHT:
btn = Quartz.kCGMouseButtonRight
down = Quartz.kCGEventRightMouseDown
up = Quartz.kCGEventRightMouseUp
else:
assert False, "button argument not in ('left', 'middle', 'right')"
return
for i in range(num):
_click(x, y, button, i+1)
time.sleep(interval)
def _sendMouseEvent_2(ev, x, y, button, num):
mouseEvent = Quartz.CGEventCreateMouseEvent(None, ev, (x, y), button)
Quartz.CGEventSetIntegerValueField(mouseEvent, Quartz.kCGMouseEventClickState, num)
Quartz.CGEventPost(Quartz.kCGHIDEventTap, mouseEvent)
改__init__.py文件
@_genericPyAutoGUIChecks
def click(
x=None, y=None, clicks=1, interval=0.0, button=PRIMARY, duration=0.0, tween=linear, logScreenshot=None, _pause=True
):
button = _normalizeButton(button)
x, y = _normalizeXYArgs(x, y)
# Move the mouse cursor to the x, y coordinate:
_mouseMoveDrag("move", x, y, 0, 0, duration, tween)
_logScreenshot(logScreenshot, "click", "%s,%s,%s,%s" % (button, clicks, x, y), folder=".")
if sys.platform == 'darwin':
failSafeCheck()
if button in (LEFT, MIDDLE, RIGHT):
platformModule._multiClick(x, y, button, clicks, interval)
else:
for i in range(clicks):
failSafeCheck()
if button in (LEFT, MIDDLE, RIGHT):
platformModule._click(x, y, button)
time.sleep(interval)
@_genericPyAutoGUIChecks
def doubleClick(x=None, y=None, interval=0.0, button=LEFT, duration=0.0, tween=linear, logScreenshot=None, _pause=True):
# Multiple clicks work different in OSX
if sys.platform == "darwin":
x, y = _normalizeXYArgs(x, y)
_mouseMoveDrag("move", x, y, 0, 0, duration=0, tween=None)
x, y = platformModule._position()
platformModule._multiClick(x, y, button, 2)
_logScreenshot(logScreenshot, 'click', '%s,2,%s,%s' % (button, x, y), folder='.')
else:
# Click for Windows or Linux:
click(x, y, 2, interval, button, duration, tween, logScreenshot, _pause=False)
哦对,如果你是以下几种方法想模拟双击都会因为缺少CGEventSetIntegerValueField而导致无法打开文件
mouse.click(Button.left, 2)
#或者
mouse.press(Button.left)
mouse.release(Button.left)
mouse.press(Button.left)
mouse.release(Button.left)