LoginSignup
13
9

More than 3 years have passed since last update.

pyautoguiを【超適当に】マルチディスプレイ環境に対応させる Part1

Last updated at Posted at 2020-08-28

目的

pyautoguiをマルチディスプレイ環境下でも使いたい、より正確にはマルチディスプレイ環境下のサブディスプレイ内で画像認識させたい。

環境

python 3.8.5
pyautogui 0.9.50
pyscreez 0.1.26
OS windows限定

調査内容

参考:pyautoguiのlocateOnScreen()がマルチディスプレイ非対応な理由
上記記事にて、以下の記述を発見。

PILのimageGrab.grab()がデュアルディスプレイに対応していない

これを読んでおや?と思い、imageGrab.grab()の定義を確認してみた。

imageGrab.py
def grab(bbox=None, include_layered_windows=False, all_screens=False, xdisplay=None):
grab()
all_screens=False

それっぽい引数を確認、いつからかは知らないが少なくともpython3.8.5ではgrab関数も変更されているっぽい。

実装内容

OSがWindowsの時、pyautoguiのlocateOnScreen()内でimage.grab()を呼び出しているのは以下の関数。

pyscreez--__init__.py
def _screenshot_win32(imageFilename=None, region=None):
    """
    TODO
    """

    # TODO - Use the winapi to get a screenshot, and compare performance with ImageGrab.grab()
    # https://stackoverflow.com/a/3586280/1893164
    im = ImageGrab.grab()

    if region is not None:
        assert len(region) == 4, 'region argument must be a tuple of four ints'
        region = [int(x) for x in region]
        im = im.crop((region[0], region[1], region[2] + region[0], region[3] + region[1]))
    if imageFilename is not None:
        im.save(imageFilename)
    return im

なので、imageGrab.grab()に引数を渡してやる、それだけ。

pyscreez--__init__.py
def _screenshot_win32(imageFilename=None, region=None):
    """
    TODO
    """

    # TODO - Use the winapi to get a screenshot, and compare performance with ImageGrab.grab()
    # https://stackoverflow.com/a/3586280/1893164
    #im = ImageGrab.grab()
    im = ImageGrab.grab(all_screens=True)

    if region is not None:
        assert len(region) == 4, 'region argument must be a tuple of four ints'
        region = [int(x) for x in region]
        im = im.crop((region[0], region[1], region[2] + region[0], region[3] + region[1]))
    if imageFilename is not None:
        im.save(imageFilename)
    return im

結果

サブディスプレイでも画像認識ができるようになった。

問題点

ディスプレイの並びが

[1][2][3]

[1][2]
[3][4]

のように行儀よく並んでいるならばよいのだが

[2][1][3] (我が家の配置)

のように並んでいると、locateOnScreenが返すのは[2]のLeftTopを(0,0)とした座標なのに対し、windows側が要求するのは[1]のLeftTopを(0,0)とした座標となってしまう。

この問題はwin32apiにモニターを列挙して座標を返すapiがあるので、次回それを利用して解決したいと思う。
今回はここまで。

13
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
9