マイナビニュースマイナビ

ウインドウを配置するスクリプト - 外部ディスプレイ対応編(ファイナル)

【連載】

PowerShell Core入門 - 基本コマンドの使い方

【第171回】ウインドウを配置するスクリプト - 外部ディスプレイ対応編(ファイナル)

[2021/10/22 08:00]後藤大地 ブックマーク ブックマーク

これまで数回にわたり、PowerShellからWindows APIを利用してウインドウの移動やサイズの変更などを行ってきた。その取り組みも今回で最後だ。

先に、今回解説するスクリプトの最終版「window_deploy.ps1」を以下に示しておく。

#!/usr/bin/env pwsh

#====================================================================
# ウインドウ配置スクリプト
#====================================================================

#====================================================================
# 引数を処理
#====================================================================
Param(
    [String]$ProcessName="*",   # プロセス名
    [String]$WindowTitle=".*",  # ウインドウタイトル(正規表現)
    [Int32]$X="0",          # ウインドウ左上X座標。負値は右下逆X座標
    [Int32]$Y="0",          # ウインドウ左上Y座標。負値は右下逆Y座標
    [Int32]$Width="-1",     # ウインドウ幅
    [Int32]$Height="-1",        # ウインドウ高
    [Double]$XRatio="0",        # ウインドウ左上X座標。負値は右下逆X座標
                    # (スクリーン幅を1とし、0~1の実数で指定)
    [Double]$YRatio="0",        # ウインドウ左上Y座標。負値は右下逆Y座標
                    # (スクリーン高を1とし、0~1の実数で指定)
    [Double]$WidthRatio="-1",   # ウインドウ幅(スクリーン幅を1とし、0~1の実数で指定)
    [Double]$HeightRatio="-1",  # ウインドウ高(スクリーン高を1とし、0~1の実数で指定)
    [Switch]$WindowProcessList  # ウインドウプロセス一覧を表示
)

#====================================================================
# ウインドウプロセスを一覧表示
#====================================================================
if ($WindowProcessList) {
    Get-Process                         | 
    ? {$_.MainWindowHandle -ne 0 }              | 
    Format-Table -Property Id,ProcessName,MainWindowTitle
    exit
}

#====================================================================
# Win32 APIのインポート
#====================================================================
Add-Type @"
using System;
using System.Runtime.InteropServices;

public struct RECT
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}

public class WinAPI
{
    // ウインドウの現在の座標データを取得する関数
    [DllImport("user32.dll")]
    public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

    // ウインドウの座標を変更する関数
    [DllImport("user32.dll")]
    public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); 

    // スクリーンサイズを取得する関数
    [DllImport("user32.dll")]
    public static extern int GetSystemMetrics(int nIndex); 
}
"@

#====================================================================
# ウインドウを配置する関数 Deploy-Window
#====================================================================
function Deploy-Window {
    param (
        $wh  # ウインドウハンドラ
    )

    # スクリーン幅を取得
    $screenWidth = [WinAPI]::GetSystemMetrics(0);

    # スクリーン高さを取得
    $screenHeight = [WinAPI]::GetSystemMetrics(1);

    # ウインドウ座標データ構造体
    $rc = New-Object RECT

    # ウインドウの現在の座標データを取得
    [WinAPI]::GetWindowRect($wh, [ref]$rc) > $null

    # マイナス指定のXおよびYを正値へ変換
    if ($X -lt 0) {
        $X = $screenWidth + $X - $Width
    }
    if ($Y -lt 0) {
        $Y = $screenHeight + $Y - $Height
    }

    # 割合指定をXおよびYの正値へ変換
    if ($XRatio -gt 0) {
        $X = $screenWidth * $XRatio
    }
    elseif ($XRatio -lt 0) {
        $X = $screenWidth + ($screenWidth * $XRatio) - $Width
    }
    if ($YRatio -gt 0) {
        $Y = $screenHeight * $YRatio 
    }
    elseif ($YRatio -lt 0) {
        $Y = $screenHeight + ($screenHeight * $YRatio) - $Height
    }

    # 割合指定をWidthの値へ変換
    if ($WidthRatio -ge 0) {
        $Width = $screenWidth * $WidthRatio
    }
    # 幅指定がない場合、現在の幅を設定
    elseif ($Width -eq -1) {
        $Width = $rc.Right - $rc.Left;
    }

    # 割合指定をHeightの値へ変換
    if ($HeightRatio -ge 0) {
        $Height = $screenHeight * $HeightRatio
    }
    # 高指定がない場合、現在の高を設定
    elseif ($Height -eq -1) {
        $Height = $rc.Bottom - $rc.Top;
    }

    # ウインドウを指定された座標に指定されたサイズで配置する
    [WinAPI]::MoveWindow($wh, $X, $Y, $Width, $Height, $true) > $null
}

#====================================================================
# 対象となるウインドウを選択し、サイズを変更
#====================================================================
Get-Process -Name $processName |
    ? { $_.MainWindowHandle -ne 0 } |
    ? { $_.MainWindowTitle -match "$windowTitle" } |
    % {
        # ウインドウを配置
        Deploy-Window($_.MainWindowHandle);
}

このスクリプトでは座標(X、Y、幅、高さ)をピクセルで指定でき、XとYの指定がマイナス値だった場合、右下からの距離として動作する。また、スクリーンサイズを1とした比率指定で座標(X、Y、幅、高さ)を指定することもでき、こちらもXとYの比率がマイナス値だった場合、右下からの距離としてカウントする。

比率による座標の指定ができることで、スクリーンの解像度が変わっても同じ場所に配置することができる。ウインドウを思い通りの場所に配置するスクリプトとしては、このぐらいまで実装しておけば十分だろう。

実用例:ワークスペース配置スクリプト

では、window_deploy.ps1を使った例を見てみよう。次のスクリプトをご覧いただきたい。このスクリプトはアプリケーションの起動と、配置(X、Y、幅、高さ)を行っている。座標の指定に比率指定を行っているところがポイントで、ディスプレイの解像度が変わっても同じように配置できる。

#!/usr/bin/env pwsh

#====================================================================
# アプリケーション起動とデプロイ
#====================================================================

# マイナビニュース 企業IT 新着記事一覧
$cmd='C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe'
$url='https://news.mynavi.jp/list/headline/business/enterprise/'
& $cmd --new-window $url

Sleep 1
window_deploy "*" "新着記事.*" 0 0 -1 -1 0.04 0 0.55 0.555

# マイナビニュース IT Search+
$cmd='C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe'
$url='https://news.mynavi.jp/itsearch/'
& $cmd --new-window $url

Sleep 1
window_deploy "*" "TECH+.*" 0 0 -1 -1 0.04 0.55 0.55 0.42

# Windows Terminal
wt
Sleep 1
window_deploy WindowsTerminal ".*" 0 0 -1 -1 -0.415 0 0.417 0.85

# メモ帳
notepad
Sleep 1
window_deploy notepad ".*" 0 0 -1 -1 -0.415 0.845 0.417 0.125

実行すると次のようになる(ここではディスプレイの解像度がそれぞれ3840x2160、1920x1080、1280x700で実行したものを示す)。

ディスプレイ解像度 3840x2160で実行

ディスプレイ解像度 1920x1080で実行

ディスプレイ解像度 1280x700で実行

解像度は変わっているものの、比率で指定しているため同じ場所にウインドウが配置されていることがおわかりいただけるだろうか。これなら、もし会社で使う外部ディスプレイと自宅で使う外部ディスプレイの解像度が異なっていても同じように使うことができる。

PowerShellスクリプトで作業効率アップ

ほかの配置設定も自動化したければ、同じ要領でスクリプトを作成すればよい。例えばWebサーフィン用、プログラミング用、事務作業用、趣味の楽譜作成用など、目的に応じてスクリプトを用意すればよいのだ。

MicrosoftはWindows 11でスナップレイアウト(「Windows」+「Z」)を拡張しており、配置できるパターンを増やしている。通常の使用であれば、これでもう十分だろう。しかし、より使いやすいウインドウの配置を追求するのであれば、スナップレイアウトでは対応できない。そんなときは今回紹介したスクリプトを使えばばっちりである。

実際に自分で作業してみるとわかると思うが、目の前でアプリケーションが起動して自分の指定した場所へリサイズしながらポンポンと移動していく様子は、なかなか気持ちが良い。試しに自分のこだわりのポジションを整理し、それをスクリプトに落とし込んでみていただきたい。気づけば手放せないスクリプトになっているはずだ。

※ 本記事は掲載時点の情報であり、最新のものとは異なる場合がございます。予めご了承ください。

一覧はこちら

連載目次

もっと知りたい!こちらもオススメ

【連載】RPA入門 - ツールで学ぶ活用シーン

【連載】RPA入門 - ツールで学ぶ活用シーン

AIには、ルールベース、機械学習、深層学習(ディープラーニング)の3つのレベルがあり、レベルが上がるに連れてより高度な人工知能を実現しますが、AIのスピンオフという位置付けで、Digital Labor(仮想知的労働者)によるホワイトカラー業務の自動化を実現するRPAが注目されています。

関連リンク

この記事に興味を持ったら"いいね!"を Click
Facebook で TECH+ の人気記事をお届けします
注目の特集/連載
[解説動画] Googleアナリティクス分析&活用講座 - Webサイト改善の正しい考え方
Slackで始める新しいオフィス様式
Google Workspaceをビジネスで活用する
人生を豊かにするパラレルキャリア~VUCA時代に新しい生き方を選ぶ理由とは~
ニューノーマル時代のオウンドメディア戦略
ミッションステートメント
次世代YouTubeクリエイターの成長戦略
IoTでできることを見つけるための発想トレーニング
教えてカナコさん! これならわかるAI入門
AWSではじめる機械学習 ~サービスを知り、実装を学ぶ~
Kubernetes入門
SAFeでつくる「DXに強い組織」~企業の課題を解決する13のアプローチ~
マイクロサービス時代に活きるフレームワーク Spring WebFlux入門
AWSで作るマイクロサービス
マイナビニュース スペシャルセミナー 講演レポート/当日講演資料 まとめ
セキュリティアワード特設ページ

一覧はこちら

今注目のIT用語の意味を事典でチェック!

一覧はこちら

会員登録(無料)

ページの先頭に戻る