~UI Automationで画面操作捕捉!その5 ~ UI Automation with PowerShell 奮戦記 11日目

UI Automation*1で遊ぼう!

UI Automation の画面操作の捕捉機能を使用した画面ハードコピーの自動化に挑戦しています。Windowsの標準実装のみ、PowerShellのみで動作させることを目指しています。

UI Automationでの画面操作の捕捉をPowerShellで出来るようにEventタイプを.Net Framworkで実装しました。
実装した開発ライブラリ、共通で使用するスクリプトについては以下を確認してくださいね。
https://amon52280sub.hateblo.jp/entry/2019/01/23/032420


画像保存機能を追加しました。
これで画面ハードコピーの自動化
まだ色々調整は必要ですが動きます。
PowerShell Version3(管理者権限)で実行してみる。

[CmdletBinding()]
Param (
  [string]$global:path = (".\Screen\{0}\{1}" -f (hostname),((Get-Date).ToString("yyyyMMdd"))),
  [string]$global:filename = "Screen",
  [int]$global:delay = 500
)

if (test-path $path) {
}
else {
  mkdir -Force $path
}

# UI Automation 共通ファンクションを組み込む
. .\UIA.ps1

# アセンブリを読み込む
Add-Type -AssemblyName System.Drawing

# スクリーンショット保存
function global:SaveScreenShot([int]$width,[int]$height,[int]$x,[int]$y)
{
  $filepath = ("{0}\{1}{2}.bmp" -f $path,$filename,(Get-Date).ToString("yyyyMMddhhmmss"))
  Write-Host $filepath

  #Bitmapオブジェクト
  $bmp = New-Object System.Drawing.Bitmap($width, $height)

  #BitmapオブジェクトからGraphicsオブジェクトを作成
  $g = [System.Drawing.Graphics]::FromImage($bmp)
  #スクリーンショットを取得
  $g.CopyFromScreen($x, $y, 0, 0, $bmp.Size)

  #画像ファイルを保存
  Write-Debug $PSCommandPath
  [System.IO.Directory]::SetCurrentDirectory((Split-Path $PSCommandPath))
  $bmp.Save($filepath) 
}

# 初期化
$global:uia = UIA_Init

# Timer イベント捕捉
$global:timer = New-Object System.Timers.Timer
$timer.Interval = 100
$timer.Enabled = $false
Register-ObjectEvent -InputObject $timer -EventName Elapsed -Action {
  try {
  $name = $ev[0].current.name
  $controltype = $ev[0].current.localizedcontroltype
  $classname = $ev[0].current.classname
  $eventid = $ev[1].EventId.ProgrammaticName
  Write-Host $(UIA_OutPut -element $ev[0] -event $ev[1] -mode Event | Out-String)
  #Write-Host $(UIA_GetParentElement $ev[0] | fc | Out-String)

  # ウインドウ or ダイアログ 
  $p = UIA_GetParentElement $ev[0]
  Write-Host $($p | Out-String)
  Write-Host ($p -ne $null)
  if ($p -ne $null) {
    # 枠幅計算 試行中
    $bw = (Get-ItemPropertyValue -Path 'HKCU:\Control Panel\Desktop\WindowMetrics' -Name BorderWidth) / 15
    $pbw = (Get-ItemPropertyValue -Path 'HKCU:\Control Panel\Desktop\WindowMetrics' -Name PaddedBorderWidth) / 15
    $dpi = (Get-ItemPropertyValue -Path 'HKCU:\Control Panel\Desktop\WindowMetrics' -Name AppliedDPI) * 0.01
    $dx = [math]::Round($dpi * $bw) + [math]::Round($dpi * $pbw) 
    $width = $p.current.BoundingRectangle.width + ($dx * 2)
    $height = $p.current.BoundingRectangle.height + $dx
    $x = $p.current.BoundingRectangle.x - $dx
    $y = $p.current.BoundingRectangle.y
    SaveScreenShot $width $height $x $y
  }
  Write-Host $(UIA_OutPut -element $ev[0] -event $ev[1] -mode Event | Out-String)
  Write-Host $($ev[0].GetSupportedPatterns() | Out-String)
  $timer.Enabled = $false
  } catch {
    Write-Host $_
  }
} | Out-Null

# UI Automation イベント捕捉
Register-ObjectEvent -InputObject $uia -EventName UIChange -Action {
  try {
  #$timer.Enabled = $false

  if ($args -eq $null) {return}
  if ($args[0] -eq $null) {return}
  $global:ev = $args
  $name = $ev[0].current.name
  $controltype = $ev[0].current.localizedcontroltype
  $classname = $ev[0].current.classname
  $eventid = $ev[1].EventId.ProgrammaticName

  if ($name -match "powershell") {return}
  switch ($eventid) {
    "AutomationElementIdentifiers.AutomationFocusChangedEvent" {
      $timer.Enabled = $false
      $uia.SetEvent($ev[0])
      $timer.Interval = $delay
      $timer.Enabled = $true
    }
    "AutomationElementIdentifiers.AutomationPropertyChangedEvent" {
      $timer.Enabled = $false
      $timer.Interval = $delay
      $timer.Enabled = $true
    }
    "WindowPatternIdentifiers.WindowOpenedProperty"{
      Write-Host $(UIA_OutPut -element $ev[0] -event $ev[1] -mode Event | Out-String)
      $timer.Enabled = $false
      $timer.Interval = $delay
      $timer.Enabled = $true
    }
    ("WindowPatternIdentifiers.WindowClosedProperty"){
      #$timer.Interval = $delay
      #$timer.Enabled = $false
    }  
    default {
      Write-Host $(UIA_OutPut -element $ev[0] -event $ev[1] -mode Event | Out-String)
      $timer.Interval = $delay
      $timer.Enabled = $false
    }
  }
  #Write-Host $(UIA_OutPut -element $ev[0] -event $ev[1] -mode Event | Out-String)
  } catch {
    Write-Host $_
  }  
} | Out-Null

# イベントスタート
$uia.StartEvent()
"自動画面ハードコピースタート!!"

スクリプトだから修正、調整が楽ですねー。
後はちょこっと調整と画面ハードコピーの時、何か効果(音or絵)とか追加したいですね。

*1:ここでのUI AutomationはSystem.Windows.Automationのことです