これまでにウインドウのサイズを変更するスクリプトと、ウインドウを移動させるスクリプトを作ってきた。この2つのスクリプトを組み合わせると、ウインドウを任意の場所に任意のサイズで配置することが可能になる。

ウインドウを任意の位置に任意のサイズで配置することができるようになると、デスクトップのアプリケーション配置を自動的に行うことが可能になる。仕事などで日々作業していると、ある程度アプリケーションウインドウの配置が決まってくるものだ。ここにはこのアプリケーション、こっちにこのアプリケーションを置いておくといった具体だ。今回は、スクリプトでその配置処理を自動化しよう。

Windowsは左右や上下への配置に関してはウインドウを貼り付けておくことができるが、それ以外の配置はそれほど得意ではない。より細かい配置をPowerShellスクリプトを使って行うことで、「いつものデスクトップ」を素早く整えてしまおう。

window_deploy.ps1

ではさっそく結果となる「window_deploy.ps1」から見てみよう。

#!/usr/bin/env pwsh

#====================================================================
# 引数を処理
#====================================================================
Param(
    [String]$ProcessName="*",   # プロセス名
    [String]$WindowTitle=".*",  # ウィンドウタイトル(正規表現)
    [Int32]$X="0",              # ウィンドウ左上X座標
    [Int32]$Y="0",              # ウィンドウ左上Y座標
    [Int32]$Width="0",          # ウィンドウ幅
    [Int32]$Height="0",         # ウィンドウ高さ
    [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);
}
"@

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

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

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

    # 幅の指定がない場合、取得した座標データからウィンドウの幅を計算
    if ($Width -eq 0) {
        $Width = $rc.Right - $rc.Left;
    }

    # 高さの指定がない場合、取得した座標データからウィンドウの高さを計算
    if ($Height -eq 0) {
        $Height = $rc.Bottom - $rc.Top;
    }

    # マイナス指定のXおよびYを正値へ変換
    if ($X -lt 0) {
        # スクリーン幅を取得
        $screenWidth = [WinAPI]::GetSystemMetrics(0);
        # Xの値を算出
        $X = $screenWidth + $X - $Width
    }
    if ($Y -lt 0) {
        # スクリーン高さを取得
        $screenHeight = [WinAPI]::GetSystemMetrics(1);
        # Yの値を算出
        $Y = $screenHeight + $Y - $Height
    }

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

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

ベースとしては前回仕上げたwindow_move.ps1からの書き換えがわかりやすい。どのように書き換えを行ったかwindow_move.ps1との変更分を次に掲載しておく。

--- window_move.ps1 2021-09-16 19:44:04.892607000 +0900
+++ window_deploy.ps1   2021-09-16 19:44:07.860428000 +0900
@@ -6,8 +6,10 @@
 Param(
    [String]$ProcessName="*",   # プロセス名
    [String]$WindowTitle=".*",  # ウィンドウタイトル(正規表現)
-   [Int32]$X="0",              # ウィンドウ幅
-   [Int32]$Y="0",              # ウィンドウ高さ
+   [Int32]$X="0",              # ウィンドウ左上X座標
+   [Int32]$Y="0",              # ウィンドウ左上Y座標
+   [Int32]$Width="0",          # ウィンドウ幅
+   [Int32]$Height="0",         # ウィンドウ高さ
    [Switch]$WindowProcessList  # ウィンドウプロセス一覧を表示
 )

@@ -53,9 +55,9 @@
 "@

 #====================================================================
-# ウィンドウを移動する関数 Move-Window
+# ウィンドウを配置する関数 Move-Deploy
 #====================================================================
-function Move-Window {
+function Deploy-Window {
    param (
        $wh  # ウィンドウハンドラ
    )
@@ -66,26 +68,32 @@
    # ウィンドウの現在の座標データを取得
    [WinAPI]::GetWindowRect($wh, [ref]$rc) > $null

-   # 取得した座標データからウィンドウの幅と高さを計算
-   $width = $rc.Right - $rc.Left;
-   $height = $rc.Bottom - $rc.Top;
+   # 幅の指定がない場合、取得した座標データからウィンドウの幅を計算
+   if ($Width -eq 0) {
+       $Width = $rc.Right - $rc.Left;
+   }

+   # 高さの指定がない場合、取得した座標データからウィンドウの高さを計算
+   if ($Height -eq 0) {
+       $Height = $rc.Bottom - $rc.Top;
+   }
+
    # マイナス指定のXおよびYを正値へ変換
    if ($X -lt 0) {
        # スクリーン幅を取得
        $screenWidth = [WinAPI]::GetSystemMetrics(0);
        # Xの値を算出
-       $X = $screenWidth + $X - $width
+       $X = $screenWidth + $X - $Width
    }
    if ($Y -lt 0) {
        # スクリーン高さを取得
        $screenHeight = [WinAPI]::GetSystemMetrics(1);
        # Yの値を算出
-       $Y = $screenHeight + $Y - $height
+       $Y = $screenHeight + $Y - $Height
    }

-   # ウィンドウのサイズはそのままに、左上の場所を変更
-   [WinAPI]::MoveWindow($wh, $X, $Y, $width, $height, $true) > $null
+   # ウィンドウを指定された座標に指定されたサイズで配置する
+   [WinAPI]::MoveWindow($wh, $X, $Y, $Width, $Height, $true) > $null
 }

 #====================================================================
@@ -95,6 +103,6 @@
    ? { $_.MainWindowHandle -ne 0 } |
    ? { $_.MainWindowTitle -match "$windowTitle" } |
    % {
-       # ウィンドウを移動
-       Move-Window($_.MainWindowHandle);
+       # ウィンドウを配置
+       Deploy-Window($_.MainWindowHandle);
 }

次にそれぞれの変更分を見ていこう。

パラメータに幅と高さを追加

window_move.ps1はウィンドウを移動するスクリプトだ。このため、パラメータに幅と高さは含まれていない。追加するのは以下のコードだ。

Param(
    [String]$ProcessName="*",   # プロセス名
    [String]$WindowTitle=".*",  # ウィンドウタイトル(正規表現)
    [Int32]$X="0",              # ウィンドウ左上X座標
    [Int32]$Y="0",              # ウィンドウ左上Y座標
    [Int32]$Width="0",          # ウィンドウ幅
    [Int32]$Height="0",         # ウィンドウ高さ
    [Switch]$WindowProcessList  # ウィンドウプロセス一覧を表示
)

今回のスクリプトはウインドウを任意の場所に配置するためにX座標、Y座標、幅、高さを指定する。このためここで上記のように-Widthと-Heightが追加してある。

パラメータで幅と高さが指定されていない場合には、現在のウインドウの幅と高さを使いたい。この判断をするのに、幅と高さのデフォルト値として「0」を指定している。幅や高さが「0」だった場合には、現在のウインドウのサイズを指定して使うようにする。

Deploy-Window()関数

window_move.ps1ではMove-Window()関数でウインドウを移動させていた。今度は移動とサイズ指定と両方行うので、以下のように名前をDeploy-Window()へ変更する。

function Deploy-Window {

この関数で変更するのは幅の指定と高さの指定だけだ。幅や高さの値が「0」だった場合、ユーザーから幅や高さの指定が行われていないとし、次のように現在のウインドウの幅や高さを取得して設定するようにする。

    # 幅の指定がない場合、取得した座標データからウィンドウの幅を計算
    if ($Width -eq 0) {
        $Width = $rc.Right - $rc.Left;
    }

    # 高さの指定がない場合、取得した座標データからウィンドウの高さを計算
    if ($Height -eq 0) {
        $Height = $rc.Bottom - $rc.Top;
    }

Windows APIの呼び出し部分をちょっと調整してこの関数は完成だ。

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

Deploy-Window()関数呼び出し部分を変更

最後に、これまでMove-Window()関数を呼び出していた部分を、Deploy-Window()関数を呼び出すように変更すればスクリプトは完成だ。

+       # ウィンドウを配置
+       Deploy-Window($_.MainWindowHandle);

さっそく使ってみよう

作ったスクリプトを実行してみよう。次のように座標とサイズを指定して実行する。

window_deply -ProcessName msedge -X 100 -Y 100 -Width 1200 -Height 800

実行結果

座標もサイズも指定できる。そして座標はマイナス値も指定できるので、次のような指定方法も可能だ。

window_deploy -ProcessName msedge -X -100 -Y -100 -Width 1500 -Height 1000

実行結果

座標の指定は正値と負値を組み合わせることもできる。

window_deploy -ProcessName msedge -X 700 -Y -100 -Width 1000 -Height 1300

実行結果

こんな感じでウインドウを自由に配置できるようになると、複数のアプリケーションを同時に好きな場所に配置するといったことができるようになる。今回はその基盤となるスクリプトを作成した。次回は、具体的にどうやって配置スクリプトを作成すればよいかについて説明する。