2016年3月4日金曜日

ウインドウ名に AmaRecTV という文字列が含まれていて、クラスリストに Display が含まれてたら、それはもう AmaRecTV でいいですよね?

はじめに 

IkaLogの自動録画で使っているControlAmarecTV.au3にコードを追加して、AmaRecTVのフレーム無しウインドウのハンドルを取れるようにできたと思ったけど一定の条件で不具合が出るから結局ダメだったっぽいの続きになります。

お約束をお読みになった上で、イカよろしくおねがいいたします。

IkaLogさんのGitHubにコードが採用されました!(2016年6月9日追記)
余分なコードを除いてシンプルになっていますので、こちらをご覧ください。


せっかくここまで追加したのに、何か他の方法がないかなーと漠然と考えていたのですが、ウインド名以外で判定できれば大丈夫なのではとひらめきました。

調べたら、WinGetClassListというのを見つけました。

どんなのか、メッセージボックスに出しつつ調べると、AmaRecTVからは

msctls_statusbar32" & @LF & "Display" & @LF & "ToolbarWindow32" & @LF

というクラスリストが文字列になって取れるっぽくて、フレーム無しの時は "Display" & @LFだけになるっぽいです。


ウインドウ名に AmaRecTV という文字が含まれていて、クラスに Display が含まれてたら、それはもう AmaRecTV でいいですよね?

これでも、100%の判別にはならないかなー
その辺りが良くわからないのです……

実験に使用したコード


実際にIkaLogと連動させての動作確認は行っていません。
もしお使いになる場合は、事前に動作確認を行ってください。
テストの方法等は、ひとつ前の記事をご覧ください。

コードを表示するパーツのせいか、コードが変に化けているみたいなので、テキストファイルを用意しました。
(こちらをクリックしてください。)

※コードを表示するパーツをコピペで導入してるから、取り方が分からないのです…

;
;
;  IkaLog
;  ======
;  Copyright (C) 2015 Takeshi HASEGAWA
;
;  Licensed under the Apache License, Version 2.0 (the 'License');
;  you may not use this file except in compliance with the License.
;  You may obtain a copy of the License at
;
;      http://www.apache.org/licenses/LICENSE-2.0
;
;  Unless required by applicable law or agreed to in writing, software
;  distributed under the License is distributed on an 'AS IS' BASIS,
;  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;  See the License for the specific language governing permissions and
;  limitations under the License.

;
;  Start and stop recording using Open Broadcaster Software(OBS).
;
;  To Start Recording:
;    ControlAmarecTV.au3 start
;
;  To Stop Recording:
;    ControlAmarecTV.au3 stop
;
;  To Reanem the recording:
;    If you want to rename the recording to a specific filename,
;    Specifcy the filename as environment variables
;    IKALOG_MP4_DESTDIR and IKALOG_MP4_DESTNAME.
;
;  Though this script will sleep seconds so that work on
;  a specific environment. The behavior is subject to change.
;

#include 
#include 

;
;注意! 
;コマンドプロンプトからの動作確認は行っていますが、IkaLogと連動させての確認はまだ行っていません。
;もし利用される場合は、事前に動作確認を行ってタイミングの調整を行ってください。

;自分の好みに合わせて値を設定してください。
;Sendキーの詳しい書き方については https://www.autoitscript.com/autoit3/docs/appendix/SendKeys.htm
Global $SendStartkeyValue = "{F8}" ;送信する録画開始キー
Global $SendStopkeyValue = "{F9}" ;送信する録画終了キー
Global $StartSleepSec = 0    ;録画開始待機時間(秒)
Global $StopSleepSec = 8    ;録画終了待機時間(秒)
Global $RenameSleepSec = 10   ;リネーム処理待機時間(秒) リネーム機能は使ってないので、値が正しいかわかりません。

Global $IniFileName = "ControlAmarecTV.exe" ;無視してください。

;ウインドハンドル取得のサンプル動作用
Const $AmaChkTitle = "AmaRecTV"  ;AmaRecTVハンドル取得用文字列
Const $AmaClassNF  = "Display" & @LF ;AmaRecTV 3.10フレーム無し時のクラスリスト
;Const $AmaClass  = "msctls_statusbar32" & @LF & "Display" & @LF & "ToolbarWindow32" & @LF ;AmaRecTV 3.10フレーム有り時のクラスリスト


Func RenameFile($source)
 Local $dest = EnvGet('IKALOG_MP4_DESTNAME')
 $dest = StringReplace($dest, "/", "\")
 If $dest = '' Then
  Return False
 EndIf

 ; IkaLog assumes mp4 as video file extension, but AmarecTV uses avi.
 If StringRight($dest, 4) = ".mp4" Then
  $dest = StringReplace($dest, ".mp4", ".avi", -1)
 EndIf

 FileMove($source, $dest, $FC_OVERWRITE)
EndFunc

Func FindRecentRecording()
 ; Replace all slashes to backslashes.
 ; $directory also needs a backslash at its end.
 $directory = StringReplace($directory, "/", "\")
 If StringRight($directory, 1) <> "\" Then
  $directory = $directory & "\"
 EndIf

 Local $hSearch = FileFindFirstFile($directory & "*.avi*")

 If $hSearch = -1 Then
  MsgBox(0, "Error", "Could not find any candinates in " & $directory & " (path 1)", 10)
  Return False
 EndIf

 Local $latest_file = ''
 Local $latest_timestamp = ''

 While True
   Local $file = FileFindNextFile($hSearch)
   If @error Then ExitLoop

   Local $timestamp = FileGetTime($directory & $file, $FT_MODIFIED, $FT_STRING)
   If StringCompare($timestamp, $latest_timestamp) > 0 Then
   $latest_file = $directory & $file
   $latest_timestamp = $timestamp
   EndIf
 WEnd

 FileClose($hSearch)

 If $latest_file = '' Then
   MsgBox(0, "Error", "Could not find any candinates in " & $directory & " (path 2)", 10)
   Return False
 EndIf

 Return $latest_file
EndFunc

Func ControlAmarecTV($stop)
   Local $hWnd = WinWait('[CLASS:AmaRecTV; INSTANCE:2]', '', 1)

   If $hWnd = 0 Then
   MsgBox(0, "Error", "Could not find AmarecTV")
   Return False
   EndIf

   Local $text = ControlGetText($hWnd, "", "[CLASS:msctls_statusbar32]")
   Local $inRecording = StringInStr($text, '録画中...') > 0

   ;問題は、フレーム無し時のウインドウハンドル値が異なる事だけだと気付く
   Local $hWndDsp = $hWnd ;テスト表示用 処理的には不要
   Local $var = AmarecTVWinHandleValue()
   If ($var[0] <> "") And ($hWnd <> $var[1]) Then
   $hWnd = $var[1]
   EndIf

   Local $click = False
   If $inRecording and $stop Then
   ;Stop Recording.
   $click = True
   ElseIf (Not $inRecording) and (Not $stop) Then
   ; Start Recording.
   $click = True
   EndIf

   If $click Then
   If $stop Then
   ; 録画終了待ち時間
   Sleep(1000 * $StopSleepSec)
   Else
   ; 録画開始待ち時間
   Sleep(1000 * $StartSleepSec)
   EndIf

   WinActivate($hWnd)
   WinWaitActive($hWnd, "", 1)

   If $stop Then
   ; 録画停止キー送る
   Send($SendStopkeyValue)
   Else
   ; 録画開始キー送る
   Send($SendStartkeyValue)
   EndIf


   If $stop Then
   Local $directory = EnvGet('IKALOG_MP4_DESTDIR')
   If (StringLen($directory) <> 0) Then
   Sleep(1000 * $RenameSleepSec)
   Local $file  = FindRecentRecording()
   RenameFile($file)
   EndIf

   EndIf
   EndIf

   ;MsgBox(0, $var[0]  , $hWndDsp & @LF & $hWnd & @LF &  $var[1]  & @LF & $text , 5) ;テスト表示

EndFunc


;AmarecTVのハンドルとウインドタイトルを取得する(サンプルコードをそのまま流用)
;AmaRecTVに含まれるクラス名が含まれてたらAmaRecTVと認識するようにしました。
;http://open-shelf.appspot.com/AutoIt3.3.6.1j/html/functions/WinList.htm
Func AmarecTVWinHandleValue()
   Local $var = WinList()
   Local $retValue[2]
   $retValue[0] = "" ;ウインドウタイトル
   $retValue[1] = 0 ;ウインドウハンドル

   For $i = 1 to $var[0][0]
   ; 可視で名前のあるウィンドウのみ
   If $var[$i][0] <> "" AND IsVisible($var[$i][1]) Then

   ;MsgBox(64, "Details", "Title=" & $var[$i][0] & @LF & "Handle=" & $var[$i][1], 10)
   ;MsgBox(64, $var[$i][0] , "ClassList=" & WinGetClassList($var[$i][0]), 10)

   ;AmaRecTVを探す
   If (StringInStr($var[$i][0], $AmaChkTitle)) Then  ;タイトルに AmaRecTVが含まれる
   If (StringInStr(WinGetClassList($var[$i][0]), $AmaClassNF)) Then ;Display
      $retValue[0] = $var[$i][0]
      $retValue[1] = $var[$i][1]
      Return $retValue
   EndIf
   EndIf
   EndIf
   Next

   Return $retValue
EndFunc

Func IsVisible($handle)
   If BitAnd( WinGetState($handle), 2 ) Then
   Return 1
   Else
   Return 0
   EndIf
EndFunc

;AmarecTVの枠表示の状態を確認
Func AmarecTVHandleMonitor()

 Local $var = AmarecTVWinHandleValue()
 Local $title = $var[0]
 Local $hWnd = $var[1]
 If $hWnd = 0 Then
   MsgBox(0, "取得できた情報", "AmarecTV いないっぽい。")
   Return False
 EndIf

 Local $text = ControlGetText($hWnd, "", "[CLASS:msctls_statusbar32]")
 If ($text = "") Then
   Local $ident = "枠なしっぽい?"
 Else
   $ident = "□枠ありっぽい!□"
 EndIf

   Local $hCnd = ControlGetHandle($hWnd, "", "[CLASS:msctls_statusbar32]")

   Local $hWndIka = WinWait('[CLASS:AmaRecTV; INSTANCE:2]', '', 1) ;オリジナルのハンドル取得
   Local $textIka = ControlGetText($hWnd, "", "[CLASS:msctls_statusbar32]") ;オリジナルの文字列取得

   $msg = StringFormat("ウインドウタイトル: %s%s", $title, @LF)
   $msg = StringFormat("%sオリジナルのハンドル: %s%s", $msg,  $hWndIka,  @LF)
   $msg = StringFormat("%sサンプルのハンドル : %s%s", $msg,  $hWnd,  @LF)
   $msg = StringFormat("%sオリジナルで取れる値: %s%s", $msg, $textIka, @LF)
   $msg = StringFormat("%sウインド下部の文字列: %s%s", $msg, $text, @LF)
   $msg = StringFormat("%sウインド下部の文字列を表示しているコントロールのハンドル: %s%s", $msg, $hCnd, @LF)
   $msg = StringFormat("%s枠の判定: %s", $msg, $ident)
   MsgBox(0, "取得できた情報", $msg)

EndFunc


;main

;スクリプトの設置先を取得(無視してください)
$IniFileName = StringFormat("%s", @ScriptFullPath)

;オプション無しで起動した時は、使い方と現在のiniの値を表示する。
if ($CmdLine[0] = 0) Then
   Local $title = "起動オプションが必要です"
   Local $msg = StringFormat("%s%s",     "--- 使い方---", @LF)
   $msg = StringFormat("%s%s%s%s%s",$msg, "録画開始:", @ScriptFullPath, " start", @LF)
   $msg = StringFormat("%s%s%s%s",  $msg, "録画終了:", @ScriptFullPath, " stop" & @LF & @LF)
   $msg = StringFormat("%s%s%s",     $msg, "--- 現在の設定 --- ", @LF)
   $msg = StringFormat("%s%s%s%s",  $msg, "スクリプトの設置パス: ", $IniFileName, @LF)
   $msg = StringFormat("%s%s%s%s",  $msg, "録画開始キー: ", $SendStartkeyValue, @LF)
   $msg = StringFormat("%s%s%s%s",  $msg, "録画終了キー: ", $SendStopkeyValue, @LF)
   $msg = StringFormat("%s%s%s%s",  $msg, "録画開始待ち秒: ", $StartSleepSec, @LF)
   $msg = StringFormat("%s%s%s%s",  $msg, "録画終了待ち秒: ", $StopSleepSec,  @LF)
   $msg = StringFormat("%s%s%s%s",  $msg, "リネーム待ち秒: ", $RenameSleepSec, @LF)
   $msg = StringFormat("%s%s",      $msg, @LF)
   $msg = StringFormat("%s%s%s",    $msg, "[はい]を押すと何もせずこのまま終了します。", @LF)
   $msg = StringFormat("%s%s%s",    $msg, "[いいえ]を押すと表示中のウインドからAmaRecTVを探す処理を実行します。", @LF)
   If (MsgBox(4+64, $title, $msg, 60) = 7) Then
        AmarecTVHandleMonitor()
   EndIf
Else
   $stop = StringCompare($CmdLine[1], 'stop') == 0
   ControlAmarecTV($stop)
EndIf


古い情報かも知れませんが、AmaRecTVって最小化してたらCPU負荷が下がるらしいです。

2 件のコメント:

  1. 起動オプションを割り当てて起動しているのに起動オプションが必要ですと言われます。。。

    返信削除
  2. コマンドプロンプトでの動作チェックで動いたのに、WinIkaLogで動作しないパターンの場合はこちらで報告されているようです。
    https://github.com/hasegaw/IkaLog/issues/132

    WinIkaLogだと対応待ちになります。


    WinIkaLog, IkaLogCUI版共に手元の環境では動作しているので、何が悪いのか分かりません。
    各人の動作環境(インストールされているソフトやドライバなど全て)を調べる事は出来ないので、CUI版を入れて動作をトレースしてご自身で修正する事も可能だと思いますとしか、こちらでは言いようが無いのです。

    返信削除