python - 来自 Windows 子系统 linux 的 PyAutoGUI
问题描述
如何从在 WSL 中运行的 Python 代码在 Windows 中执行鼠标单击?
我尝试使用 PyAutoGUI,但是,我收到以下错误:
...
File "/usr/lib/python3.6/os.py", line 669, in __getitem__
raise KeyError(key) from None
KeyError: 'DISPLAY'
因为我使用的是wsl,所以它决定我的平台是linux。如果我将它硬编码到 Windows,ctypes 确实在 dc = ctypes.windll.user32.GetDC(0) 中有属性 win.dll
if sys.platform == 'win32':
import ctypes
if _PILLOW_INSTALLED:
from PIL import ImageGrab
# Makes this process aware of monitor scaling so the screenshots are correctly sized:
try:
ctypes.windll.user32.SetProcessDPIAware()
except AttributeError:
pass # Windows XP doesn't support this, so just do nothing.
dc = ctypes.windll.user32.GetDC(0)
class POINT(ctypes.Structure):
_fields_ = [('x', ctypes.c_long),
('y', ctypes.c_long)]
def _winPosition():
cursor = POINT()
ctypes.windll.user32.GetCursorPos(ctypes.byref(cursor))
return (cursor.x, cursor.y)
position = _winPosition
def _winScreenshot(filename=None):
# TODO - Use the winapi to get a screenshot, and compare performance with ImageGrab.grab()
# https://stackoverflow.com/a/3586280/1893164
try:
im = ImageGrab.grab()
if filename is not None:
im.save(filename)
except NameError:
raise ImportError('Pillow module must be installed to use screenshot functions on Windows.')
return im
screenshot = _winScreenshot
def _winSize():
return (ctypes.windll.user32.GetSystemMetrics(0), ctypes.windll.user32.GetSystemMetrics(1))
size = _winSize
def _winGetPixel(x, y):
colorRef = ctypes.windll.gdi32.GetPixel(dc, x, y) # A COLORREF value as 0x00bbggrr. See https://docs.microsoft.com/en-us/windows/win32/gdi/colorref
red = colorRef % 256
colorRef //= 256
green = colorRef % 256
colorRef //= 256
blue = colorRef
return (red, green, blue)
getPixel = _winGetPixel
elif platform.system() == 'Linux':
from Xlib.display import Display
import errno
scrotExists = False
try:
whichProc = subprocess.Popen(
['which', 'scrot'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
scrotExists = whichProc.wait() == 0
except OSError as ex:
if ex.errno == errno.ENOENT:
# if there is no "which" program to find scrot, then assume there
# is no scrot.
pass
else:
raise
_display = Display(os.environ['DISPLAY'])
def _linuxPosition():
coord = _display.screen().root.query_pointer()._data
return coord["root_x"], coord["root_y"]
position = _linuxPosition
def _linuxScreenshot(filename=None):
if not scrotExists:
raise NotImplementedError('"scrot" must be installed to use screenshot functions in Linux. Run: sudo apt-get install scrot')
if filename is not None:
tmpFilename = filename
else:
tmpFilename = '.screenshot%s.png' % (datetime.datetime.now().strftime('%Y-%m%d_%H-%M-%S-%f'))
if scrotExists:
subprocess.call(['scrot', '-z', tmpFilename])
im = Image.open(tmpFilename)
# force loading before unlinking, Image.open() is lazy
im.load()
if filename is None:
os.unlink(tmpFilename)
return im
else:
raise Exception('The scrot program must be installed to take a screenshot with PyScreeze on Linux. Run: sudo apt-get install scrot')
screenshot = _linuxScreenshot
def _linuxSize():
return _display.screen().width_in_pixels, _display.screen().height_in_pixels
size = _linuxSize
def _linuxGetPixel(x, y):
rgbValue = screenshot().getpixel((x, y))
return rgbValue[0], rgbValue[1], rgbValue[2]
getPixel = _linuxGetPixel
有谁知道如何解决这个问题?
解决方案
只是为了澄清...... pyautogui 不适用于 WSL?根据我在其他地方读到的内容,这与 linux 子系统中缺少 X 服务器有关。类似于 pyautogui 无法在远程或无头终端会话上工作。
所以,用普通的旧窗户试试这个,它会起作用的!
推荐阅读
- report - 如何获得 IR 搜索栏 Oracle APEX 18.2 的价值
- c# - 一个静态类常量在被调用时表现得像字符串枚举问题
- django - django admin 喜欢应用程序用户的行为
- java - 错误:尽管 IDEA 知道它们,但 java 包 xxx 不存在
- c# - AspNetCore 2.2 Angular SignalR Negotiate 总是返回 404 Not found
- visual-studio-extensions - VSIX - 次要视觉工作室版本
- javascript - 如何在透明背景的前端 Webview 中制作进度条?
- python - 如何使用python正确编码从pdf中提取的文本?
- laravel - 如何在 laravel 的分页集合中使用变换
- java - 如何从 Python 脚本中的 jar 文件调用 Java 方法