AutoHotKey_Lで、AviUtlのバッチ登録を自動化した。

 AviUtlで複数ファイルをエンコードする場合「バッチ登録」を使うのだけど、手作業で出力ファイル名入力するのが面倒すぎたので自動化した。

 変換したい動画のパスリスト(\n区切り)をクリップボードに入れて、AviUtlメインウィンドウでF12打鍵すれば登録開始。
 出力ファイルは"元ファイル名.設定した拡張子"で、重複してれば接尾辞"_[n]"で回避。
 使用前に"OutputPluginNum"と"SaveFileExt"を設定すべし。

;--------------------------------------------------------------------------------------
; AviUtl
;--------------------------------------------------------------------------------------
#IfWinActive ahk_class AviUtl ahk_exe Aviutl.exe

F12::  ; クリップボードのパスをバッチ登録
  
  OutputPluginNum := 1  ; "プラグイン出力"で選択するプラグインの番号。1番上は1。
  SaveFileExt := "mp4"  ; 出力ファイルの拡張子。
  
  
  
  PathList := Clipboard
  
  WinGet, WHwnd, ID
  WinGet, ExePath, ProcessPath
  SplitPath, ExePath, , ExeDir
  IfExist, %ExeDir%\batch*.aup
  {
    MsgBox, 262691, , バッチ登録されたプロジェクトが存在します`n既存のプロジェクトを削除しますか?
    IfMsgBox, Cancel
      return
    IfMsgBox, Yes
      FileRecycle, %ExeDir%\batch*.aup
  }
  
  StringReplace, PathList, PathList, `n, `n, UseErrorLevel
  MaxNum := ErrorLevel
  
  Loop, Parse, PathList, `n, `"
  {
    TipView(A_Index "/" MaxNum)
    
    FilePath := A_LoopField
    IfNotExist, %FilePath%
      continue
    
    SplitPath, FilePath, , FileDir, , FileNoExt
    
    SaveFilePath := FileDir "\" FileNoExt "." SaveFileExt
    while FileExist(SaveFilePath)
      SaveFilePath := FileDir "\" FileNoExt "_[" A_Index "]." SaveFileExt
    
    WinMenuSelectItem, ahk_id %WHwnd%, , ファイル, 1&  ; "開く"
    WinWait, ファイルを開く ahk_class #32770 ahk_exe Aviutl.exe
    ControlSetText, Edit1, %FilePath%  ; "ファイル名"
    Sleep, 100
    ControlClick, Button2, , , L, 2  ; "開く"
    WinWaitClose
    
    WinMenuSelectItem, ahk_id %WHwnd%, , ファイル, プラグイン出力, %OutputPluginNum%&
    WinWait, ahk_class #32770 ahk_exe Aviutl.exe
    ControlSetText, Edit1, %SaveFilePath%  ; "ファイル名"
    Sleep, 100
    ControlClick, Button5, , , L, 2  ; "バッチ登録"
    WinWaitClose
  }
  
  TipView("FIN")
return


;--------------------------------------------------------------------------------------
; TipView.ahk
;--------------------------------------------------------------------------------------

TipView(TextBuf = "", Timer = 3000, X = "", Y = "", SW = 0) {
  if SW
    CoordMode, ToolTip

  ToolTip, %TextBuf%, X, Y
  if !Timer
    Timer := "Off"
  SetTimer, TipClose, %Timer%
}

TipClose:
  SetTimer, TipClose, Off
  ToolTip
return


[PR]
# by LordNoesis | 2017-05-17 18:29 | テクノロジ | Trackback | Comments(0)

エキブロにログインできない場合の対処。

 エキサイトブログはサードパーティCookieをブロックしているとログインできないので、許可リストにhttps://idcaccounts.exblog.jpを登録する。


 Vivaldiはサイト別許可リストが標準の設定画面になく、Blink由来の設定画面にしかないので、chrome://settings/contentExceptions#cookiesに飛んで[*.]idcaccounts.exblog.jpを登録すればよい。
 なお、アドレス中の「chrome://」を「vivaldi://」に置換する雑な仕様があるので、アンカー書いたりブックマークする時は注意。


[PR]
# by LordNoesis | 2017-02-08 21:07 | テクノロジ | Trackback | Comments(0)

Win10で自作実行ファイルが「既定のプログラム」に表示されなくなったので直した。

 拙作「S2WA」を、レジストリを弄って「既定のプログラム」に登録してブラウザに振り分けするとめちゃ便利なのだが、Win7ではできてたのにWin10にアップグレードしたら「既定のプログラム」に表示されなくなった。PC設定>既定のアプリだと、表示はされるけど選択できなかったり。
 レジストリが間違ってる or Win10で変わった?EXEの権限?アンチウィルスによるブロック?等々あれやこれや、本当に何っっっ時間も悩んだ挙句、「Win10でコンパイルし直したら認識された」とか徒労感ハンパない。
 AHKで作ったEXEだけでなく、古いHSP版もダメだった。スクリプト系がブロックされてる? でも認識されないだけで動作は問題ないしなあ? あとコンパイル時の文字コードとか32bitと64bitとかUPXやMPRESSとか、気にならなくもないが検証する気力は残ってない。とりあえず認識されたからよし。


[PR]
# by LordNoesis | 2016-07-02 21:53 | テクノロジ | Trackback | Comments(0)

TabJugglerでスクロールできない問題を解決した。

 TabJugglerというタブ管理用のChrome拡張があって、すべての互換ブラウザに入れてるくらい便利なのだが、操作できなくなる問題があるので対処した。

 そもTabJugglerは、すべてのタブを対象とした「ひとつのウィンドウにまとめる」「ウィンドウを分離する」「タブの配置をソートする」という機能と、検索でリストアップした、あるいはしなかったタブを対象とした「閉じる」「分離する」という機能がある。この後者の検索で大量のタブをリストアップすると、操作ボタンが押し出されて操作不能になってしまう。大量のタブがあるからこそ使いたいのに!
 で、調べてみたら操作不能の原因はスクロールを禁じたスタイルにあったので、CSSをたった1行いじるだけで解決したという……。

 問題のCSSはExtensions\jgiplclhploodgnkcljjgddajfbmafmp\バージョン番号\assets\styles\popup.css。ExtensionsフォルダはOperaならProfile、ChromeとVivaldiならUser Data以下にあるが、識別子jgiplc(以下略)を検索した方が手っ取り早い。
 そのpopup.cssの11行目にあるoverflow: hidden;を、hiddenからscrollにすれば完了。


[PR]
# by LordNoesis | 2016-02-11 20:00 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、標準出力を得たい……。

 以前見つけた関数だと上手く動かないことがあったのでフォーラム検索したら、もっと新しいやつを見つけた。見つけたんだが、標準出力が多いと文字化けすることが発覚。ReadFileでバイト単位で取得したデータをそのままデコードしてるせいだと思うが、AHKで文字列でないデータを操作とか苦行の予感がするので、Fileオブジェクトで文字単位で取得してごまかした。
 文字化けはなくなったが、本当にこれで問題ないのかは解らん。

; https://autohotkey.com/board/topic/54559-stdin/#entry687172

  MsgBox % sOutput := StdoutToVar_CreateProcess("tasklist /s " A_ComputerName)

StdoutToVar_CreateProcess(psCmd, psInput="", psEncoding:="CP0", psDir:="", ByRef pnExitCode:=0) {
  
  DllCall("CreatePipe", PtrP, hStdInRd, PtrP, hStdInWr, Ptr, 0, UInt, 0)
  DllCall("CreatePipe", PtrP, hStdOutRd, PtrP, hStdOutWr, Ptr, 0, UInt, 0)
  DllCall("SetHandleInformation", Ptr, hStdInRd, Uint, 1, Uint, 1)
  DllCall("SetHandleInformation", Ptr, hStdOutWr, UInt, 1, UInt, 1)
  
   VarSetCapacity(pi, (A_PtrSize == 4) ? 16 : 24, 0)
  siSz := VarSetCapacity(si, (A_PtrSize == 4) ? 68 : 104, 0)
  NumPut(siSz, si, 0, "UInt")
  NumPut(0x100, si, (A_PtrSize == 4) ? 44 : 60, "UInt")
  NumPut(hStdInRd, si, (A_PtrSize == 4) ? 56 : 80, "Ptr")
  NumPut(hStdOutWr, si, (A_PtrSize == 4) ? 60 : 88, "Ptr")
  NumPut(hStdOutWr, si, (A_PtrSize == 4) ? 64 : 96, "Ptr")
  
  If (!DllCall("CreateProcess", Ptr, 0, Ptr, &psCmd, Ptr, 0, Ptr, 0, Int, True, UInt, 0x08000000
   , Ptr, 0, Ptr, psDir ? &psDir : 0, Ptr, &si, Ptr, &pi))
   return
   , DllCall("CloseHandle", Ptr, hStdOutWr)
   , DllCall("CloseHandle", Ptr, hStdOutRd)
   , DllCall("CloseHandle", Ptr, hStdInRd)
  
  DllCall("CloseHandle", Ptr, hStdOutWr ) ; The write pipe must be closed before reading the stdout.
  
  if (psInput != "")
   FileOpen(hStdInWr, "h", psEncoding).Write(psInput)
   DllCall("CloseHandle", "Ptr", hStdInWr)
  
  
; ################################################################################
  
  
  StdOutBuf := FileOpen(hStdOutRd, "h", psEncoding)
  StrBuf := 1
  while StrLen(StrBuf) {
   StrBuf := StdOutBuf.Read(2047)
   sOutPut .= StrBuf
  }
  
  
; ################################################################################
  
  
  DllCall("GetExitCodeProcess", Ptr, NumGet(pi, 0), UIntP, pnExitCode)
  DllCall("CloseHandle", Ptr, NumGet(pi, 0) )
  DllCall("CloseHandle", Ptr, NumGet(pi, A_PtrSize) )
  DllCall("CloseHandle", Ptr, hStdOutRd )
return sOutput
}


[PR]
# by LordNoesis | 2016-02-09 20:00 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、Opera12の起動を便利にしてみた。 ver.2.3.1

 セッション変換に失敗することがあったので1行だけ修正。今更使う人もいないと思うが。

; --------- --------- --------- --------- ---------
; RunOpera.ahk ver.2.3.1
; --------- --------- --------- --------- ---------

#WinActivateForce

  OperaPath := "R:\Opera"  ; Opera.exeの存在するパス。末尾"\"は不可。
  
  if %0%  ; 引数があった場合、Operaのパスと見なす
    OperaPath = %1%
  
  SessionsPath := OperaPath "\profile\sessions"  ; セッションフォルダのフルパスを指定。末尾"\"は不可。
  BookmarksPath := OperaPath "\profile\bookmarks.adr"  ; bookmarks.adrのフルパスを指定。
  
  TimeLimit := 30  ; 最終セッション退避確認ダイアログを自動でスキップするまでの秒数。
  
  AutoConvSW := 1  ; 最終セッションを退避させる場合、自動でブックマークに変換する設定。 0:変換しない。 1:変換する。
  ACMoveSW := 1  ; 自動変換(↑)したセッションを隔離する設定。 0:隔離しない。 1:隔離する。
  
  StackSW := 1  ; スタックの設定。 0:無視する。 1:スタックごとにフォルダを分ける。
  
  HisReadSW := 0  ; タブ履歴(タブで表示したページの履歴)の設定。 0:最新のみ読み込む。 1:すべて読み込む。
  His0PrefixSW := 0  ; タブ履歴がなかった場合のプレフィックスの設定。 0:なし。 1:0を明示する。
  
  WriteTrgSW := 1  ; ブックマーク情報を書き込む場所の設定。 0:セッションフォルダにテキストで保存。 1:bookmarks.adrに書き込む。
  
; --------- --------- --------- --------- ---------
  
  IfNotExist, %SessionsPath%\
  {
    MsgBox, 16, , セッションフォルダが見つかりません。`n%SessionsPath%
    ExitApp
  }
  If WriteTrgSW {
    IfNotExist, %BookmarksPath%
    {
      MsgBox, 16, , bookmarks.adrが見つかりません。`n%BookmarksPath%
      ExitApp
    }
  }
  
  IfNotExist, %SessionsPath%\autosave.win
  {
    IfExist, %SessionsPath%\autosave.win.bak
      FileMove, %SessionsPath%\autosave.win.bak, %SessionsPath%\autosave.win
  }
  IfExist, %SessionsPath%\autosave.win
  {
    FileCopy, %SessionsPath%\autosave_RunOpBak.win, %SessionsPath%\autosave_RunOpBak2.win, 1  ; ↓セッション退避etc.を実行しない時も念のため2世代バックアップ。
    FileCopy, %SessionsPath%\autosave.win, %SessionsPath%\autosave_RunOpBak.win, 1
    GoSub, SessionAnalyze
  }
  
  FileCopy, %OperaPath%\ui\fastforward_backup.ini, %OperaPath%\ui\fastforward.ini, 1  ; アップデートのたびにFastForward.iniが初期化される問題の対策。
  
  Run, %OperaPath%\opera.exe, , , OpPid
  WinWait, ahk_pid %OpPid%, , 60
  if !ErrorLevel {
    ifWinExist, Opera へようこそ ahk_pid %OpPid%
    {
      WinActivate
      WinWaitClose
    }
  } else {
    return
  }
  
  WinWait, マスターパスワードを入力してください ahk_pid %OpPid%, , 5
  If ErrorLevel
    return
  WinSet, Topmost, ON
  WinActivate
  Sleep, 300
  
ExitApp

; --------- --------- --------- --------- ---------

SessionAnalyze:
  FileRead, OSession, *P65001 *t %SessionsPath%\autosave.win
  If ErrorLevel {
    MsgBox, 48, , Sessionの読み込みに失敗しました。`n%SessionsPath%\autosave.win
    return
  }
  
  Idx := 0
  WinTitles := ""
  Loop {
    Idx := RegExMatch(OSession, "\[(\d+)history url\][\s\S]+?count=(\d+)", $, Idx + 1)
    If !Idx
      Break
    WinNum := $1
    HisNum := $2 - 1
    HisTitle := GetHisTitle(OSession, WinNum, HisNum, Idx)
    WinTitles .= " " HisTitle "`n"
  }
  If !WinTitles
    return
    
  SetTimer, RenewCount, 1000
  MsgBox, 259, 退避確認(30秒後に通常起動), 起動時に最終セッションを退避しますか?`n`n◆最終セッションの内容◆`n%WinTitles%, %TimeLimit%
  SetTimer, RenewCount, Off
  IfMsgBox, Yes
  {
    TimeNum := A_Now
    BackupName := TimeNum ".win"
    Loop {
      FileMove, %SessionsPath%\autosave.win, %SessionsPath%\%BackupName%
      If !ErrorLevel  ; 最終セッションのリネームに成功なら
        Break
      BackupName := TimeNum "_" A_Index ".win"
    }
    FileDelete, %SessionsPath%\autosave.win.bak
    If AutoConvSW
      GoSub, SessionConvert
  }
  IfMsgBox, Cancel
    ExitApp
return

; --------- --------- --------- --------- ---------

RenewCount:
  IfWinExist, 退避確認( ahk_class #32770
  {
    TimeLimit--
    WinSetTitle, 退避確認(%TimeLimit%秒後に通常起動)
    if !TimeLimit
      SetTimer, RenewCount, Off
  }
return

; --------- --------- --------- --------- ---------

SessionConvert:
  If WriteTrgSW
    FileCopy, %BookmarksPath%, %BookmarksPath%_%A_Now%  ; bookmarks.adrのバックアップは無制限なので注意
  
  CmdLine := SessionsPath "\" BackupName
  SplitPath, CmdLine, , , , SessionName
  Result := "#FOLDER`n  NAME=[Session] " SessionName "`n`n"
  ResultBuf := Result
  
  Idx := 0
  BefGroupNum := 0
  His0Prefix :=
  Loop {
    Idx := RegExMatch(OSession, "\[(\d+)\][^\[]+group=(\d+)[^\[]+\[\1history url\][^\[]+count=(\d+)", $, Idx + 1)
    If !Idx
      Break
    WinNum := $1
    GroupNum := $2
    HisNum := $3 - 1
    HisTitle := GetHisTitle(OSession, WinNum, HisNum, Idx)
    HisUrl := GetHisUrl(OSession, WinNum, HisNum, Idx)
    
    if StackSW
      if (BefGroupNum != GroupNum) {
        if BefGroupNum
          Result .= "-`n`n"
        if GroupNum
          Result .= "#FOLDER`n  NAME=[Stack] " GroupNum "`n`n"
        BefGroupNum := GroupNum
      }
    
    If !HisReadSW {  ; タブ履歴を無視する場合
      Result .= "#URL`n  NAME=" HisTitle "`n  URL=" HisUrl "`n`n"
      Continue
    }
    
    StringLen, HisNumLen, HisNum
    
    If !HisNum {
      if His0PrefixSW
        His0Prefix := "[" ZeroSupply(HisNum, HisNumLen) "] "
      Result .= "#URL`n  NAME=" HisPrefix HisTitle "`n  URL=" HisUrl "`n`n"
      Continue
    }
    Result .= "#FOLDER`n  NAME=" HisTitle "`n`n#URL`n  NAME=[" ZeroSupply(HisNum, HisNumLen) "] " HisTitle "`n  URL=" HisUrl "`n`n"
    
    Loop, %HisNum% {
      HisNum--
      HisTitle := GetHisTitle(OSession, WinNum, HisNum, Idx)
      HisUrl := GetHisUrl(OSession, WinNum, HisNum, Idx)
      Result .= "#URL`n  NAME=[" ZeroSupply(HisNum, HisNumLen) "] " HisTitle "`n  URL=" HisUrl "`n`n"
    }
    Result .= "-`n`n"
  }
  
  If (ResultBuf == Result)
    return
  Result .= "-`n`n"
  
  If WriteTrgSW {
    FileRead, BMBuf, *t *P65001 %BookmarksPath%
    StringGetPos, Idx, BMBuf, #DELETED
    if !Idx {
      StringMid, BMBufP, BMBuf, 1, Idx
      StringMid, BMBufS, BMBuf, Idx + 1
      Result := BMBufP Result BMBufS
      FileDelete, %BookmarksPath%
    }
    FileAppend, %Result%, %BookmarksPath%, CP65001
  } Else {
    FileDelete, %CmdLine%.txt
    FileAppend, %Result%, %CmdLine%.txt, CP65001
  }
  
  If ACMoveSW {
    IfNotExist, %SessionsPath%\AutoConv\
      FileCreateDir, %SessionsPath%\AutoConv\
    FileMove, %CmdLine%, %SessionsPath%\AutoConv\%BackupName%
    If ErrorLevel
      MsgBox, 48, , 変換済みセッションの移動に失敗しました。`n%SessionsPath%\AutoConv\
  }
return

; --------- --------- --------- --------- ---------

GetHisTitle(OSession, WinNum, HisNum, Idx){
  RegExMatch(OSession, "\[" WinNum "history title\][\s\S]+?" HisNum "=(.*?)\r?\n", $)
  return $1
}

GetHisUrl(OSession, WinNum, HisNum, Idx){
  RegExMatch(OSession, "\[" WinNum "history url\][\s\S]+?" HisNum "=(.*?)\r?\n", $)
  return $1
}

ZeroSupply(Num, NumDigit){
  StringLen, NumLen, Num
  LoopNum := NumDigit - NumLen
  Loop, %LoopNum%
    Num := 0 Num
  return, Num
}


[PR]
# by LordNoesis | 2016-02-05 18:50 | テクノロジ | Trackback | Comments(0)

Windowsを遠隔操作するAndroidアプリをいくつか試してみた。

 外出先から自宅のWindows7機を遠隔操作したくて、有名処のAndroidアプリをいくつか試したメモ。

Chromeリモートデスクトップ -- 接続が簡単だが機能は貧弱。
RD Client -- Windowsのリモートデスクトップクライアントほぼそのまま。
VNC Viewer -- 普通のVNCクライアント。
TeamViewer -- 接続が簡単で一通りのことはできる。

Chromeリモートデスクトップ

 Google製。あらかじめPC側にChromeリモートデスクトップをインストールしておく必要がある(サーバーはサービスプロセス)。利用にはGoogleアカウントが必要だが、それによって一覧から対象PCを選択するだけで接続できる。WAN越えに特別な操作を必要としない。
 接続中は画面下にポップアップが出現し続ける。

 マウス入力はスワイプでポインタを動かして行う。ミドルクリック不可。ホイール(トリプルスワイプ)は敏感でちょっと使いにくい。
 キー入力はAndroidの入力そのままで補助がないため、ファンクションキー等を入力するにはBluetoothキーボードが必要。

 映像の更新頻度はまずまず。マルチモニタ対応(巨大なデスクトップとして表示)。
 音声転送には非対応。


 気軽に接続して、文字入力とマウスだけで完結する作業に向いてる。ログオンするとか、他の遠隔操作サーバー起動するとか。

RD Client

 Microsoft製。PC側でリモートデスクトップ接続を許可しておく必要がある(サーバーはサービスプロセス)。WAN越えには接続先のIPアドレスとポート解放が必要。利用ポートの変更はレジストリをいじる必要があるので、ルータで変換できないと面倒。諸々考慮するとVPN経由が楽かも。
 接続するとPC側はログオフした状態になる。

 マウス入力はスワイプでポインタを動かすモードと、タッチで直接操作するモードがある。ミドルクリック不可。
 キー入力はAndroidの入力に加え、ファンクション等が用意されたソフトウェアキーボードがある。

 映像の更新頻度は低い。マルチモニタ非対応。Aeroは解除される。
 音声転送は架空のオーディオデバイス経由。音質はまずまず。


 Windowsのリモートデスクトップクライアントほぼそのまま。AndroidでWindowsにログオンする(PC側はログオフする)のをどう考えるか。

VNC Viewer

 RealVNC製。PC側でVNCサーバーを起動しておく必要がある(今回はUltraVNCを使っている。サービス起動も可)。WAN越えには接続先のIPアドレスとポート解放が必要。通信の暗号化には有償版RealVNCが必要なので、無償でWAN越えするならVPN必須。
 サーバー側で、接続前に可否ダイアログを表示したり、接続数を制限することもできる。

 マウス入力はスワイプでポインタを動かして行う。マウス用ソフトウェアキーボードもある。
 キー入力はAndroidの入力に加え、ファンクション等が用意されたソフトウェアキーボードがある。ちゃんとAHKが入力に反応する。

 映像はサーバー設定による。更新間隔はまずまず。設定によってはGUI更新を検出できないことも。マルチモニタ非対応。
 音声転送非対応。


 普通のVNCクライアント。速度や映像関連の性質はサーバーにもよる。色数落とせば軽快だが、VPN必須なのをどう考えるか。

TeamViewer

 TeamViewer製。PC側でTeamViewerを起動しておく必要がある。利用にはアカウント登録か、接続先TeamViewerに表示されるIDとパスワードが必要。WAN越えに特別な操作を必要としない。
 接続中は画面右下にポップアップが表示され続ける。

 マウス入力はスワイプでポインタを動かして行う。ミドルクリック不可。Windows8以降ではマルチタッチ対応らしい。タブレット端末だとRDClientのようなタッチ操作もできるらしい。
 キー入力はAndroidの入力に加え、ファンクション等が用意されたソフトウェアキーボードがある。ちゃんとAHKが入力に反応する。

 映像は設定による。更新間隔はいまひとつで、GUI更新を検出できないことも(動画は問題ないっぽい)。マルチモニタ対応(モニタ切り替え)。
 音声転送に特別な操作は不用だが、音質は荒い。


 接続が簡単で、特殊キーにも対応し、音声転送も可能なので、迷ったらこれか? PC側で再生してる動画を見れなくもない。
 使い込んでないので、リモートデスクトップ以外の機能はわからん。


 総評は、うーん。簡易作業はChromeリモートデスクトップで、それ以外はVNCかなぁ。VPN構築済みでなければ、速度優先設定のTeamViewer。とにかくキビキビ動作し更新されるのが好きなんで。
 RDClientはタッチモードが便利なんだけど、Aeroやウィンドウ配置に影響あるのがなぁ。


[PR]
# by LordNoesis | 2015-11-24 21:39 | テクノロジ | Trackback | Comments(0)

数値特化のリネームソフト、ZeroSuper ver.2.1.0公開。

 複数の数値に対応したゼロサプライ(ゼロパディング、ゼロフィル、ゼロ埋めとも)、ゼロサプレス、全角の英数字と一部記号の半角変換を行う、数値特化のリネームソフト「ZeroSuper」を更新。

 ZeroSuperがどんなものかは、以前書いた説明を見よう!

 ver.2.1.0ではコマンドラインオプションに対応。バッチ等から呼び出せば、ウィンドウを表示せずに処理することが可能になった。
 詳しい説明はReadme読んでもらうとして、例をあげると、ZeroSuper.exe /M2 "001.txt" "2.txt"とか、対象パスのリストを作っといてZeroSuper.exe /M2 /L "TargetList.txt"とかやればリネームされる。簡単。
 パス指定はワイルドカードも使えるので、通常のGUI操作より便利なこともあるかもだ。

 ただし注意がいくつか。
 まず、無効なパスは無視されるということ。/L "存在しないファイル" "001.txt"とした時、ZSerは001.txtをパスリストと認識してしまう。あとパスリストの文字コード(UTF-16)が間違っていると、無効なパスとしてすべて無視されるので、これも注意。
 それと、スイッチ(/から始まるやつ)は必ずパスより先に書くこと。パスより後だと、なんか読み取れんかった。

LORD PLAIN > software > ZeroSuper


[PR]
# by LordNoesis | 2015-09-10 20:12 | テクノロジ | Trackback | Comments(0)

数値特化のリネームソフト、ZeroSuper ver.2.0.0公開。

 複数の数値に対応したゼロサプライ(ゼロパディング、ゼロフィル、ゼロ埋めとも)、ゼロサプレス、全角の英数字と一部記号の半角変換を行う、数値特化のリネームソフト「ZeroSuper」を2年ぶりに更新!

 そもそもZeroSuperってなんぞや?というと、ファイル/フォルダ名に含まれる複数の数値(半角数字がひとつ以上連続したもの)を比較し、ゼロサプライするソフト。数値は出現順にIDが割り当てられ、すべての対象ファイル/フォルダ名の同一IDの数値と比較され、ゼロサプライされる。
 例えば、[2015-06-05]と[平成27年6月5日]をゼロサプライすると、後者が[平成0027年06月05日]になる。ゼロサプレス→ゼロサプライすると、前者が[2015-6-5]になる。

 今はどうだか知らないが、開発当時は複数の数値に対応しているだけでも珍しかった。

 今回リリースされたver.2.0.0と、ver.1.1.0との違いは以下の通り。

  • Unicodeに対応
  • 実行ログをウィンドウに表示するように
  • 設定ツールを本体機能として取り込み
  • フォルダの再帰処理に対応(フォルダ自体でなく、フォルダ内のファイルをリネーム対象に)
  • 数値の出現順(ID)を無視した処理に対応(すべての数値を比較したゼロサプライに対応)
  • 完了時の通知に対応(ダイアログ or バルーン)
  • 実行ログの保存方法の変更に対応(出力しない or 毎回別のファイルに出力 or ひとつのファイルに上書き)

 AHKでいちから作り直したもんだから、まだバグが含まれている可能性もあるので、とにかく自己責任で。

c0031643_1923367.png

c0031643_19235862.png

LORD PLAIN > software > ZeroSuper


[PR]
# by LordNoesis | 2015-06-05 18:53 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、標準出力を得る方法。

 新しいの

 AHKでCUIアプリの吐く標準出力を得る方法が分からんかったので調べたらフォーラムにあったのでメモ。

 日本語環境用にラスト1行だけ書き換えた。

; http://www.autohotkey.com/board/topic/15455-stdouttovar/page-8#entry540600

MsgBox % sOutput := StdoutToVar_CreateProcess("tasklist /s " A_ComputerName)

StdoutToVar_CreateProcess(sCmd, bStream = False, sDir = "", sInput = "") {
  DllCall("CreatePipe", "UintP", hStdInRd , "UintP", hStdInWr , "Uint", 0, "Uint", 0)
  DllCall("CreatePipe", "UintP", hStdOutRd, "UintP", hStdOutWr, "Uint", 0, "Uint", 0)
  DllCall("SetHandleInformation", "Uint", hStdInRd , "Uint", 1, "Uint", 1)
  DllCall("SetHandleInformation", "Uint", hStdOutWr, "Uint", 1, "Uint", 1)
  VarSetCapacity(pi, 16, 0)
  NumPut(VarSetCapacity(si, 68, 0), si)  ; size of si
  NumPut(0x100 , si, 44)      ; STARTF_USESTDHANDLES
  NumPut(hStdInRd , si, 56)    ; hStdInput
  NumPut(hStdOutWr, si, 60)    ; hStdOutput
  NumPut(hStdOutWr, si, 64)    ; hStdError
  If Not DllCall("CreateProcess", "Uint", 0, "Uint", &sCmd, "Uint", 0, "Uint", 0, "int", True, "Uint", 0x08000000, "Uint", 0, "Uint", sDir ? &sDir : 0, "Uint", &si, "Uint", &pi)  ; bInheritHandles and CREATE_NO_WINDOW
    ExitApp
  DllCall("CloseHandle", "Uint", NumGet(pi,0))
  DllCall("CloseHandle", "Uint", NumGet(pi,4))
  DllCall("CloseHandle", "Uint", hStdOutWr)
  DllCall("CloseHandle", "Uint", hStdInRd)
  If sInput <>
  DllCall("WriteFile", "Uint", hStdInWr, "Uint", &sInput, "Uint", StrLen(sInput), "UintP", nSize, "Uint", 0)
  DllCall("CloseHandle", "Uint", hStdInWr)
  bStream ? (bAlloc:=DllCall("AllocConsole"),hCon:=DllCall("CreateFile","str","CON","Uint",0x40000000,"Uint",bAlloc ? 0 : 3,"Uint",0,"Uint",3,"Uint",0,"Uint",0)) : ""
  VarSetCapacity(sTemp, nTemp:=bStream ? 64-nTrim:=1 : 4095)
  Loop
    If DllCall("ReadFile", "Uint", hStdOutRd, "Uint", &sTemp, "Uint", nTemp, "UintP", nSize:=0, "Uint", 0)&&nSize
    {
      NumPut(0,sTemp,nSize,"Uchar"), VarSetCapacity(sTemp,-1), sOutput.=sTemp
      If bStream&&hCon+1
        Loop
          If RegExMatch(sOutput, "[^\n]*\n", sTrim, nTrim)
            DllCall("WriteFile", "Uint", hCon, "Uint", &sTrim, "Uint", StrLen(sTrim), "UintP", nSize:=0, "Uint", 0)&&nSize ? nTrim+=nSize : ""
          Else Break
    }
    Else Break
  DllCall("CloseHandle", "Uint", hStdOutRd)
  bStream ? (DllCall("Sleep","Uint",1000),hCon+1 ? DllCall("CloseHandle","Uint",hCon) : "",bAlloc ? DllCall("FreeConsole") : "") : ""
  Return StrGet(&sOutput,"CP932")
}

 なんで探してたかって、es.exe(コマンドライン版Everything)をAHKから使いたかったんすよ。これでSearchResult := StdoutToVar_CreateProcess("es.exe 検索文字列")とかやれば超便利。

 例えば、以前書いたパスリストをX-Finderのクリップフォルダに変換するスクリプトと組み合わせるとか? テキスト介せばlist2xf.exeでも同じことできるけど。


[PR]
# by lordnoesis | 2014-06-10 20:20 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、Sz7内のジャンプ移動してみた。

 axpathlist2.spiはとても便利なんだが、リストが長大になると探索が大変で、フォルダ分けされてればビューアのフォルダ移動機能で楽できるのになーと思ったので、AHKでそれっぽくがんばってみた。

 空行でパス群を区切ったSz7を用意し、MassiGraでAlt+Up/Downすれば、フォルダ移動みたいな感じで次/前のパス群までジャンプする。例によって、MassiGra以外にも応用できるはず。

 ただし、Sz7に記述されたパスのリンク切れなどによって、ファイル名に含まれる連番と、パスの記述順がズレるとジャンプもズレる。ビューア側からは有効パスの連番しかわからず、それを元にSz7を走査してアタリをつけているので。

;--------------------------------------------------------------------------------------
; MassiGra
;--------------------------------------------------------------------------------------
#IfWinActive ahk_class TF811202_MassiGra_Main

; Sz7中の次/前のファイル群(空行区切り)までジャンプ

!Up::Sz7Jump(0)
!Down::Sz7Jump(1)

Sz7Jump(SW) {
  WinGet, WHwnd, ID
  WinGetTitle, WTitle, ahk_id %WHwnd%
  if !RegExMatch(WTitle, "i)^([^<]+\.sz\d+)\\([^<]+)\.[^<]+(?:\s+<.+)?$", $)
    return
  Sz7Path := $1
  ItemNum := $2
  
  FileRead, Sz7Buf, *t *P932 %Sz7Path%
  Sz7Buf := "`n`n" Sz7Buf
  
  if SW {  ; 次
    if !RegExMatch(Sz7Buf, "^(?:\n+[^\n]+){" ItemNum ",}?\n{2,}[^\n]+\.([^\n\.]+)", $)
      return
  } else {  ; 前
    if !RegExMatch(Sz7Buf, "^(?:\n+[^\n]+){0," ItemNum - 2 "}\n{2,}[^\n]+\.([^\n\.]+)", $)
      return
  }
  TxtBuf := $
  FileExt := $1
  
  ErrorLevel := 0
  while !ErrorLevel
    StringReplace, TxtBuf, TxtBuf, `n`n, `n, All
  
  StringReplace, TxtBuf, TxtBuf, `n, `n, UseErrorLevel
  DropFiles(WHwnd, Sz7Path "\" ZeroSup(ErrorLevel, 9) "." FileExt)
}



ZeroSup(Num, NumDigit) {
  RegExMatch(Num, "^0*+(\d*)$", $)
  StringLen, NumLen, $1
  LoopNum := NumDigit - NumLen
  Loop, %LoopNum%
    $1 := 0 $1
  return, $1
}


DropFiles(hwnd, files, ptX=0, ptY=0, fNC=False) {  ; AutoHotkey スレッド part11 >>332
  static char_type:= A_IsUnicode ? "UShort" : "UChar"
    , char_size := A_IsUnicode ? 2 : 1
    , isUnicode := A_IsUnicode ? 1 : 0
  files := RTrim(files, "`r`n`t ") . "`n`n"
  byte_length := StrLen(files) * char_size
  Loop, Parse, files
    If (A_LoopField = "`n")
      NumPut(0x00, files, (A_Index-1) * char_size, char_type)
  
  hDrop := DllCall("GlobalAlloc", "UInt", 0x42, "UInt",20 + byte_length, "Ptr")
  p := DllCall("GlobalLock", "Ptr", hDrop)
  NumPut(20 , p + 00, "Int") ; offset
  NumPut(ptX , p + 04, "Int") ; pt.x
  NumPut(ptY , p + 08, "Int") ; pt.y
  NumPut(fNC , p + 12, "Int") ; fNC
  NumPut(isUnicode, p + 16, "Int") ; fWide
  DllCall("RtlMoveMemory", "Ptr", p + 20, "Str", files, "UInt", byte_length)
  DllCall("GlobalUnlock", "Ptr", hDrop)
  PostMessage, WM_DROPFILES := 0x233, hDrop , 0, , ahk_id %hwnd%
  if ErrorLevel
    MsgBox, DropFiles Err %errorlevel%
}

 たぶん、問題ない(ジャンプ先検出の正規表現に辿り着いたのかなり偶然なのでry)。

 axpathlist2.spi(てかSz7)自体がフォルダ分けに対応してればさー。あと、ファイル名とか内臓Docで元のパスわかるようにするとかー、リンク切れはダミー画像とかー、Unicode対応とかー、別のSz7のインクルードとかー、ワイルドカードとかー、相対パスとかさー、などと好き勝手いってたら、相対パスにはとっくの昔に対応済みだったという恥ずかしエピソードが。


[PR]
# by lordnoesis | 2014-02-26 20:00 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、メディアプレーヤーを目覚ましアラームに。

 快適な目覚めのためには、時間をかけて徐々に目覚める必要があり、それに音楽を使うというのは知られた方法だが、音量までタイマー操作できるハード/ソフトってそうなくね? てかAHKで操作すればよくね? というわけで書いた。

 ウチはサブのオーディオデバイスのみスピーカーに繋がっている構成なので、出力するオーディオデバイスが選択できて、かつシンプルなプレーヤーということでQonohaを使った。自由度それなりに書いたので、その辺は各自適当に。

;--------------------------------------------------------------------------------------
; Qonoha
;--------------------------------------------------------------------------------------
#IfWinActive ahk_class QonohaPlayerMainWnd

F12::
  SetTimer, AAlarmRun, Off
  ;~ TipView()

  Loop {
    InputBox, AlarmTimeSet, AudioAlarm, アラーム時刻を24時間表記で入力してください`n例:午後1時5分 => 1305, , , 150
    if ErrorLevel
      return
    if RegExMatch(AlarmTimeSet, "([0-1][0-9]|2[0-3])([0-5][0-9])", $)
      break
  }
  AlarmH := $1
  AlarmM := $2

  AlarmTime := A_Now
  if (A_Hour > AlarmH) || (A_Hour == AlarmH && A_Min >= AlarmM) {
    AlarmTxt := "明日"
    EnvAdd, AlarmTime, 1, D
  } else {
    AlarmTxt := "本日"
  }

  FormatTime, AlarmTime, %AlarmTime%, yyyyMMdd'%AlarmH%%AlarmM%00'

  FormatTime, AlarmTxt, %AlarmTime%, %AlarmTxt%HH時mm分
  MsgBox, 262177, AudioAlarm, %AlarmTxt% にセットします。
  IfMsgBox, Cancel
    return

  FormatTime, AlarmTxt, %AlarmTime%, アラーム日時:dd日HH時mm分

  EnvSub, AlarmTime, , S
  if !AlarmTime {
    MsgBox, 262160, AudioAlarm, %AlarmTxt%を過ぎています。
    return
  }

  ;~ TipView(AlarmTxt, AlarmTime "000", 0, 0)
  SetTimer, AAlarmRun, -%AlarmTime%000
return

AAlarmRun:
  AudioFilePath := "C:\Users\Public\Music\Sample Music\Sleep Away.mp3"  ; 再生したいファイルのパス。
  SplitPath, AudioFilePath, AudioFileName

  PlayerPath := "C:\Qonoha\Qonoha.exe"
  PlayerTitle := AudioFileName " ahk_class QonohaPlayerMainWnd"
  VolUpKey := "Up"  ; 音量を上げるキー
  VolDnKey := "Down"  ; 音量を下げるキー

  VolMax := 25  ; 音量の最大値(VolUpKeyを何回叩くか)
  VolMaxPeriod := 3600000  ; 音量が最大になるまでにかかる時間(ミリ秒)

  Run, "%PlayerPath%" "%AudioFilePath%"
  WinWait, %PlayerTitle%
  Send, {%VolDnKey% %VolMax%}  ; 音量をゼロに

  VolUpWait := VolMaxPeriod / VolMax
  MACnt := 0
  SetTimer, AAlarmSnooze, %VolUpWait%

  MsgBox, 262208, AudioAlarm, %AlarmTxt% になりました。`n`n%AudioFileName%
  SetTimer, AAlarmSnooze, Off
  WinClose, %PlayerTitle%
return

AAlarmSnooze:
  MACnt++
  WinActivate, %PlayerTitle%
  Send, {%VolUpKey%}
  WinActivate, AudioAlarm ahk_class #32770
  if (VolMax <= MACnt)
    SetTimer, AAlarmSnooze, Off
return

 セット後にアラーム時刻を表示したいなら、コメントアウトしてあるTipView()を使う。

;--------------------------------------------------------------------------------------
; TipView.ahk
;--------------------------------------------------------------------------------------

TipView(TextBuf = "", Timer = 3000, X = "", Y = "", SW = 0) {
  if SW
    CoordMode, ToolTip

  ToolTip, %TextBuf%, X, Y
  if !Timer
    Timer := "Off"
  SetTimer, TipClose, %Timer%
}

TipClose:
  SetTimer, TipClose, Off
  ToolTip
return


[PR]
# by lordnoesis | 2014-02-16 22:15 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、パスリストをX-Finderのクリップフォルダに変換。Ver.1.2

 先々週書いたEverythingの検索結果をX-Finderで開くシリーズの最新版なんだけど、関数をEverything以外でも使えるようにしてみた。これで\n区切りのパスリストがあれば、なんでもサムネで確認できるよ!やったねry
 もっと機能追加してからPostしようと思って大していじらず1週間たってしまったのでエターナる前にPost。

 使用例は相変わらずEverything。検索結果の任意のアイテムを選択状態にしてF11を打鍵すると、X-Finderでクリップフォルダとして開く。Ctrl+F11なら、前回のクリップフォルダに追加。

 Everything以外は各自勝手に。InputBoxでIni名指定できたらブックマーク的に使えて便利かも。

 デフォルトのIni名にプレフィックスつけたんで、X-Finderのクリップフォルダ設定に;Extra:%X-Finder%CF_*.iniと加えとくと便利。

;--------------------------------------------------------------------------------------
; Everything
;--------------------------------------------------------------------------------------
#IfWinActive ahk_class ahk_class EVERYTHING

F11::
  #ClipboardTimeout 200000
  
  ClipWaitNull()
  Send, ^c
  ClipWait, 3
  if !ErrorLevel {
    CFPath := Path2ClipFld(Clipboard, "CF_Everything.ini")
    Run, "C:\X-Finder\XF.exe" "Extra:%CFPath%"  ; X-Finderのフルパス。
  }
  ClipWaitRestore()
return

^F11::
  #ClipboardTimeout 200000
  
  ClipWaitNull()
  Send, ^c
  ClipWait, 3
  if !ErrorLevel {
    CFPath := Path2ClipFld(Clipboard, "CF_Everything.ini", 1)
    Run, "C:\X-Finder\XF.exe" "Extra:%CFPath%"  ; X-Finderのフルパス。
  }
  ClipWaitRestore()
return


Path2ClipFld(PathList, ClipFldPath = 0, AddSW = 0) {  ; Ver.1.2
  XFPath := "C:\X-Finder\"  ; パスリストのデフォルト保存先。
  if ClipFldPath {
    IfNotInString, ClipFldPath, :\
      ClipFldPath := XFPath ClipFldPath
  } else {
    ClipFldPath := XFPath "CF_.ini"
  }
  
  StringReplace, PathList, PathList, `n, `n, UseErrorLevel
  PathNum := ErrorLevel + 1
  
  if AddSW
    IniRead, IniCnt, %ClipFldPath%, X-Finder, Count, 0
  else
    IniCnt := 0
  
  if !IniCnt
    ClipFldBuf := "[X-Finder]`nCount=" PathNum
  
  Loop, Parse, PathList, `n, `r
  {
    if ("\" == SubStr(A_LoopField, 0))
      ItemPath := SubStr(A_LoopField, 1, -1)
    else
      ItemPath := A_LoopField
    
    SplitPath, ItemPath, ItemName
    ItemNum := A_Index + IniCnt - 1
    
    ClipFldBuf .= "`nName" ItemNum "=" Str2RefStr(ItemName) "`nPath" ItemNum "=""" Str2RefStr(ItemPath) """`nType" ItemNum "=1"
  }
  
  if AddSW {
    IniCnt += PathNum
    IniWrite, %IniCnt%, %ClipFldPath%, X-Finder, Count
  } else {
    FileDelete, %ClipFldPath%
  }
  
  FileAppend, %ClipFldBuf%, %ClipFldPath%, CP932
  return, ClipFldPath
}

Str2RefStr(StrBuf) {
  Transform, StrBuf, HTML, %StrBuf%, 2
  SetFormat, Integer, H
  Loop {
    if !RegExMatch(StrBuf, "&#(\d+);", $)
      break
    
    TipNum := 0 + $1
    StringTrimLeft, TipNum, TipNum, 2
    if (0 != TipLen := 4 - StrLen(TipNum))
      Loop, %TipLen%
        TipNum := "0" + TipNum
    
    StringReplace, StrBuf, StrBuf, &#%$1%;, &#x%TipNum%;, All
  }
  SetFormat, Integer, D
  StringReplace, StrBuf, StrBuf, &, &, All
  return, StrBuf
}


ClipWaitNull(SW = 1) {
  if SW {
    global CBBackup
    CBBackup := ClipboardAll
  }
  
  Clipboard :=
  while Clipboard
    Sleep, 100
}

ClipWaitRestore() {
  global CBBackup
  
  ClipWaitNull(0)
  Clipboard := CBBackup
  ClipWait
}

 先人の作った「list2xf.exe」との違いは――AHKで応用しやすいってのと、Unicode文字対応ってあたりかなー。

 Everything Ver.1.4は普通のListViewになってたので、Clipboard経由せずControlGet, PathList, List, Selected, SysListView321, Aで取得して加工してもよい。



おまけ。
[PR]
# by lordnoesis | 2014-01-17 19:25 | テクノロジ | Trackback(1) | Comments(0)

AutoHotKey_Lで、Everythingの検索結果をX-Finderで開けるように。 Ver.1.1.1

 Everythingの検索結果をX-Finderのクリップフォルダに変換するAHKスクリプトを微修正。どうせ手作業で編集しないのだから、パスも文字参照にして、X-Finder上で扱いやすく。使い方等は前回参照。

;--------------------------------------------------------------------------------------
; Everything
;--------------------------------------------------------------------------------------
#IfWinActive ahk_class ahk_class EVERYTHING

F11::
  ClipWaitNull()
  Send, ^c
  ClipWait, 3
  if !ErrorLevel {
    Path2ClipFld(Clipboard)
    IfWinExist, ahk_class TXFinder.UnicodeClass
      WinActivate
    else
      Run, "C:\X-Finder\XF.exe"  ; X-Finderのパス。
  }
  ClipWaitRestore()
return

Path2ClipFld(PathList) {
  ClipFldPath := "C:\X-Finder\EverythingResult.ini"  ; パスリストの保存先。
  
  StringReplace, PathList, PathList, `n, `n, UseErrorLevel
  ClipFldBuf := "[X-Finder]`nCount=" ErrorLevel + 1
  
  Loop, Parse, PathList, `n, `r
  {
    if ("\" == SubStr(A_LoopField, 0))
      ItemPath := SubStr(A_LoopField, 1, -1)
    else
      ItemPath := A_LoopField
    
    SplitPath, ItemPath, ItemName
    
    ItemPath := Str2RefStr(ItemPath)
    ItemName := Str2RefStr(ItemName)
    
    ItemNum := A_Index - 1
    ClipFldBuf .= "`nName" ItemNum "=" ItemName "`nPath" ItemNum "=""" ItemPath """`nType" ItemNum "=1"
  }
  FileDelete, %ClipFldPath%
  FileAppend, %ClipFldBuf%, %ClipFldPath%, CP932
}

Str2RefStr(StrBuf) {
  Transform, StrBuf, HTML, %StrBuf%, 2
  SetFormat, Integer, H
  Loop {
    if !RegExMatch(StrBuf, "&#(\d+);", $)
      break
    
    TipNum := 0 + $1
    StringReplace, StrBuf, StrBuf, &#%$1%;, &#%TipNum%;, All
  }
  SetFormat, Integer, D
  StringReplace, StrBuf, StrBuf, &#0, &#, All
  StringReplace, StrBuf, StrBuf, &amp;, &, All
  return, StrBuf
}



ClipWaitNull(SW = 1) {
  if SW {
    global CBBackup
    CBBackup := ClipboardAll
  }
  
  Clipboard :=
  while ("" != Clipboard)
    Sleep, 50
}

ClipWaitRestore() {
  global CBBackup
  
  ClipWaitNull(0)
  Clipboard := CBBackup
  ClipWait
}


[PR]
# by lordnoesis | 2014-01-04 17:56 | テクノロジ | Trackback | Comments(3)

AutoHotKey_Lで、Everythingの検索結果をX-Finderで開けるように。

 Everything Search Engineのような、NTFSのMFTに対応した検索ソフトはとても高速だが、どうしてもMFTの情報だけでは絞り込めなかったり、条件に当てはまるファイルを俯瞰したい場合などに、エクスプローラのようなサムネイルの一覧表示が欲しくなるが、そういうソフトは中々ない。というわけで、Everythingの検索結果を、X-Finderのクリップフォルダ(任意のファイル等を集約できる仮想フォルダ)として開くAHKスクリプト書いた。

;--------------------------------------------------------------------------------------
; Everything
;--------------------------------------------------------------------------------------
#IfWinActive ahk_class ahk_class EVERYTHING

F11::
  ClipWaitNull()
  Send, ^c
  ClipWait, 3
  if !ErrorLevel {
    Path2ClipFld(Clipboard)
    IfWinExist, ahk_class TXFinder.UnicodeClass
      WinActivate
    else
      Run, "C:\X-Finder\XF.exe"  ; X-Finderのパス。
  }
  ClipWaitRestore()
return

Path2ClipFld(PathList) {
  ClipFldPath := "C:\X-Finder\EverythingResult.ini"  ; パスリストの保存先。
  
  StringReplace, PathList, PathList, `n, `n, UseErrorLevel
  ClipFldBuf := "[X-Finder]`nCount=" ErrorLevel + 1
  
  Loop, Parse, PathList, `n, `r
  {
    if ("\" == SubStr(A_LoopField, 0))
      ItemPath := SubStr(A_LoopField, 1, -1)
    else
      ItemPath := A_LoopField
    SplitPath, ItemPath, ItemName
    
    Transform, ItemName, HTML, %ItemName%, 2
    
    SetFormat, Integer, H
    Loop {
      if !RegExMatch(ItemName, "&#(\d+);", $)
        break
      
      TipNum := 0 + $1
      StringReplace, ItemName, ItemName, &#%$1%;, &#%TipNum%;, All
    }
    SetFormat, Integer, D
    StringReplace, Itemname, ItemName, &#0, &#, All
    
    Loop, %ItemPath%, 1
      ItemPath := A_LoopFileShortPath
    
    ItemNum := A_Index - 1
    ClipFldBuf .= "`nName" ItemNum "=" ItemName "`nPath" ItemNum "=""" ItemPath """`nType" ItemNum "=1"
  }
  FileDelete, %ClipFldPath%
  FileAppend, %ClipFldBuf%, %ClipFldPath%, CP932
}



ClipWaitNull(SW = 1) {
  if SW {
    global CBBackup
    CBBackup := ClipboardAll
  }
  
  Clipboard :=
  while ("" != Clipboard)
    Sleep, 50
}

ClipWaitRestore() {
  global CBBackup
  
  ClipWaitNull(0)
  Clipboard := CBBackup
  ClipWait
}

 Everythingで検索結果を選択し、F11を打鍵するとX-Finder形式のiniを吐く。ウチのX-Finderはクリップフォルダを開きっぱなしの想定なので、アクティブ化or起動に留めたが、そうでないなら引数にExtra:%X-Finder%EverythingResult.iniとでも。

 それと、ツール>基本オプション>その他>クリップフォルダへのパス登録を忘れないように。大抵の場合、既にClipFolder:があるはずなので、ClipFolder:;Extra:%X-Finder%EverythingResult.iniとなる。

 INIはS-JISでユニコード文字は文字参照という仕様なのだが、文字列中のユニコード文字だけ文字参照に置き換える簡単な方法は思いつかず、文字列すべて文字参照とショートネームにしたった。どうせ手作業で編集することなんてないしね。

voidtools > Everything
タブファイラー・X-Finder


[PR]
# by lordnoesis | 2014-01-02 19:58 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、音量ミキサーをもう少し便利に。

 WindowsVista以降の音量ミキサーを、特にキーボードで操作しやすくするAHKスクリプト Ver.1.1。

 Ver.1.0。#v打鍵で画面幅いっぱいに音量ミキサー呼び出し。上下、PageUp/Down、Home/Endキーで音量調整。ソフトウェアごとの音量は、左端のマスターボリュームの値が上限となるよう制限。左右キーで対象ソフトウェア変更。ツールチップとタイトルバーで音量の概略を表示。

 Ver.1.1。音量ミキサー起動中は、Vol.Up/Down、Muteキーでも音量ミキサーを操作するように。数字キーで対象デバイスを変更できるように。Spaceキーで対象をミュートに。対象の切り替え順が、見た目通りになるように修正。

 ver.1.2b。アイテムが10個以上あると正常動作しないのを修正。

; 音量ミキサー最大化呼び出し
#v::
  Run, SndVol.exe, , , svpid
  winWait, 音量ミキサー, , 10
  if ErrorLevel
    return
  WinGetPos, , , , WH
  WinMove, , , 0, A_ScreenHeight - WH, A_ScreenWidth
return

$Volume_Mute::
  IfWinExist, 音量ミキサー ahk_class #32770
  {
    VM_Mute()
    return
  }
  
  Send, {Volume_Mute}
return

$Volume_Down::
  IfWinExist, 音量ミキサー ahk_class #32770
  {
    VM_LvUD(0)
    return
  }
  
  Send, {Volume_Down}
return

$Volume_Up::
  IfWinExist, 音量ミキサー ahk_class #32770
  {
    VM_LvUD(1)
    return
  }
  
  Send, {Volume_Up}
return


;--------------------------------------------------------------------------------------
; 音量ミキサー
;--------------------------------------------------------------------------------------
#IfWinActive 音量ミキサー ahk_class #32770

1::VM_DevChange(1)
2::VM_DevChange(2)

Up::
  ControlGetFocus, ACtrl
  IfInString, ACtrl, msctls_trackbar32
    VM_LvUD(1)
  else
    Send, {Up}
return

Down::
  ControlGetFocus, ACtrl
  IfInString, ACtrl, msctls_trackbar32
    VM_LvUD(0)
  else
    Send, {Down}
return

PGUP::VM_LvUD(1, 20)
PGDN::VM_LvUD(0, 20)

Home::VM_LvUD(1, 100)
End::VM_LvUD(0, 100)

Right::VM_FocusMove(1)
Left::VM_FocusMove(0)

Space::
  ControlGetFocus, ACtrl
  IfInString, ACtrl, msctls_trackbar32
    VM_Mute()
  else
    Send, {Space}
return


VM_DevChange(DevNum) {
  SetKeyDelay, -1, 1
  DevVolNN := VM_GetDevTrkNN()
  DevNN := DevVolNN * 2 - 1
  
  ControlFocus, ToolbarWindow32%DevNN%
  ControlSend, ToolbarWindow32%DevNN%, {Space}{Down %DevNum%}{Enter}
  Sleep, 300
  VM_FocusMove(-1)
}

VM_LvUD(Direct = 1, MP = 1) {
  DevVolCNN := "msctls_trackbar32" VM_GetDevTrkNN()
  ControlGetFocus, AVolCNN
  if AVolCNN {
    IfNotInString, AVolCNN, msctls_trackbar32
      return
  } else
    AVolCNN := DevVolCNN
  
  SendMessage, 0x400, , , %AVolCNN%  ; TBM_GETPOS
  AVolNum := ErrorLevel
  
  if (AVolCNN != DevVolCNN) {
    SendMessage, 0x400, , , %DevVolCNN%  ; TBM_GETPOS
    DevVolNum := ErrorLevel
  } else
    DevVolNum := 0
  
  if Direct {
    if (AVolNum - MP > DevVolNum)
      VM_SetLv(AVolCNN, AVolNum - MP)
    else  ; DevVolより音量が大きくなる場合
      VM_SetLv(AVolCNN, DevVolNum)
  } else {
    VM_SetLv(AVolCNN, AVolNum + MP)
  }
  
  VM_LvView(AVolCNN, DevVolCNN)
}

VM_SetLv(AVolCNN, VolNum) {
  ControlGet, AVolHwnd, Hwnd, , %AVolCNN%
  SendMessage, 0x405, 0x1, %VolNum%, %AVolCNN%  ; TBM_SETPOS
  
  ParCNN := "#32770" RegExReplace(AVolCNN, "^msctls_trackbar32(\d+)$", "$1")
  ControlGet, ParHwnd, Hwnd, , %ParCNN%
  if ParHwnd
    SendMessage, 0x115, 0x4,%AVolHwnd%, , ahk_id %ParHwnd%  ; WM_VSCROLL
  else
    SendMessage, 0x115, 0x4,%AVolHwnd%  ; WM_VSCROLL
}

VM_Mute() {
  DevVolNN := VM_GetDevTrkNN()
  ControlGetFocus, AVolCNN
  if !AVolCNN
    AVolCNN := "msctls_trackbar32" DevVolNN
  
  if !RegExMatch(AVolCNN, "^msctls_trackbar32(\d+)$", $)
    return
  else if ($1 == DevVolNN)
    MuteCNN := "ToolbarWindow32" $1 * 2 + 1
  else
    MuteCNN := "ToolbarWindow32" $1 * 2
  ControlClick, %MuteCNN%, , , , , NA
}

VM_FocusMove(Direct = 1) {
  DevVolNN := VM_GetDevTrkNN()
  
  ControlGetFocus, AVolCNN
  if (-1 == Direct) || !RegExMatch(AVolCNN, "^(msctls_trackbar32|ToolbarWindow32)(\d+)$", $) {
    ControlFocus, msctls_trackbar32%DevVolNN%
    VM_LvView("msctls_trackbar32" DevVolNN, "msctls_trackbar32" DevVolNN)
    return
  } else if ("msctls_trackbar32" == $1) {
    AVolNN := $2
  } else if !Mod($2, 2) {
    AVolNN := $2 // 2
  } else {
    if ($2 > DevVolNN * 2)
      AVolNN := $2 // 2
    else
      AVolNN := $2 // 2 + 1
  }
  
  VolList := VM_GetTrkNNList(DevVolNN)
  
  if Direct {
    if RegExMatch(VolList, AVolNN "`n(\d+)", $)
    if RegExMatch(VolList, "(?:^|`n)" AVolNN "`n(\d+)", $)
      TrgVolNN := $1
    else
      TrgVolNN := DevVolNN
  } else {
    RegExMatch(VolList, "(\d+)(?:\n" AVolNN "|$)", $)
    TrgVolNN := $1
  }
  ControlFocus, msctls_trackbar32%TrgVolNN%
  
  VM_LvView("msctls_trackbar32" TrgVolNN, "msctls_trackbar32" DevVolNN)
}

VM_GetDevTrkNN() {
  WinGet, CList, ControlList, 音量ミキサー ahk_class #32770
  Sort, CList, P18 R
  Sort, CList, N P18 R
  Loop, Parse, CList, `n
    return SubStr(A_LoopField, 18)
}

VM_GetTrkNNList(DevVolNN) {
  static BefPosXList, Result
  
  Loop, %DevVolNN% {
    ControlGetPos, CX, , , , msctls_trackbar32%A_Index%
    PosXList .= CX "`n"
  }
  if (BefPosXList == PosXList)
    return Result
  BefPosXList := PosXList
  
  Result := ""
  Loop, %DevVolNN%
    Result .= A_Index "`n"
  Sort, Result, F VM_TrkPosXComp
  StringTrimRight, Result, Result, 1
  return Result
}

VM_TrkPosXComp(NN1, NN2) {
  ControlGetPos, CX1, , , , msctls_trackbar32%NN1%
  ControlGetPos, CX2, , , , msctls_trackbar32%NN2%
  if (CX1 > CX2)
    return 1
  else if (CX1 < CX2)
    return -1
  else
    return 0
}

VM_LvView(AVolCNN, DevVolCNN) {
  SendMessage 0x400, , , %AVolCNN%  ; TBM_GETPOS
  AVolNum := ErrorLevel
  AVolLv := 100 - AVolNum
  SendMessage 0x400, , , %DevVolCNN%  ; TBM_GETPOS
  DevVolLv := 100 - ErrorLevel
  
  WinGetTitle, AWTitle
  TitleBuf := RegExReplace(AWTitle, "(.*?) Vol:[\d/ ]+?$", "$1") " Vol:" DevVolLv
  
  LoopCnt := RegExReplace(DevVolCNN, "^msctls_trackbar32(\d+)$", "$1") - 1
  Loop, %LoopCnt% {
    SendMessage, 0x400, , , msctls_trackbar32%A_Index%  ; TBM_GETPOS
    TitleBuf .= " / " 100 - ErrorLevel
  }
  WinSetTitle, %TitleBuf%
  
  IfWinActive, 音量ミキサー ahk_class #32770
  {
    ControlGetPos, CX, CY, , CH, %AVolCNN%
    TY := CY + (CH - 24) / 100 * AVolNum - 24
    ToolTip, Vol:%AVolLv% / %DevVolLv%, %CX%, %TY%, 10  ; ToolTip番号は適当に
    SetTimer, VM_LvCheck, 100
  } else {
    ToolTip, Vol:%AVolLv% / %DevVolLv%, , , 10  ; ToolTip番号は適当に
    SetTimer, VM_LvCheck, 3000
  }
}

VM_LvCheck:
  IfWinNotActive, 音量ミキサー ahk_class #32770
  {
    ToolTip, , , , 10  ; ToolTip番号は適当に
    IfWinNotExist, 音量ミキサー ahk_class #32770
      SetTimer, VM_LvCheck, Off
  }
return

 デバイス変更は力技。

 Vol.キーで音量変更した場合、音量ミキサー非表示でもツールチップを表示しようと思ったのだが、音量ミキサーの目盛りと実際の音量が一定でなかったので断念。

c0031643_20503090.png


[PR]
# by lordnoesis | 2013-12-13 20:36 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、音量ミキサーを少し便利に。

 WindowsVista以降では、ソフトウェアごとに音量調整が可能になったが、標準の音量ミキサーはマウスだと加減しにくく、キーボード操作も微妙なのでAHK書いた。たぶんVista以降対応だと思うがWin7でしか確認してない。

 #v打鍵で画面幅いっぱいに音量ミキサー呼び出し。上下、PageUp/Down、Home/Endキーで音量調整。ソフトウェアごとの音量は、左端のマスターボリュームの値が上限となるよう制限。左右キーで対象ソフトウェア変更。ツールチップとタイトルバーで音量の概略を表示。

; 音量ミキサー最大化呼び出し
#V::
Run, SndVol.exe, , , svpid
winWait, 音量ミキサー, , 10
if errorLevel
return
WinGetPos, , , , WH
WinMove, , , 0, A_ScreenHeight - WH, A_ScreenWidth
return


;--------------------------------------------------------------------------------------
; 音量ミキサー
;--------------------------------------------------------------------------------------
#IfWinActive 音量ミキサー ahk_class #32770

Up::
ControlGetFocus, ACtrl
IfInString, ACtrl, msctls_trackbar32
AVolLvUD(1)
else
Send, {Up}
return

Down::
ControlGetFocus, ACtrl
IfInString, ACtrl, msctls_trackbar32
AVolLvUD(0)
else
Send, {Down}
return

PGUP::AVolLvUD(1, 20)
PGDN::AVolLvUD(0, 20)

Home::AVolLvUD(1, 100)
End::AVolLvUD(0, 100)

Right::VolFocusMove(1)
Left::VolFocusMove(0)

AVolLvUD(Direct = 1, MP = 1) {
ControlGetFocus, AVolCNN
IfNotInString, AVolCNN, msctls_trackbar32
return

MVolCNN := "msctls_trackbar32" GetMVolNN()

SendMessage, 0x400, , , %AVolCNN% ; TBM_GETPOS
AVolNum := ErrorLevel

if (AVolCNN != MVolCNN) {
SendMessage, 0x400, , , %MVolCNN% ; TBM_GETPOS
MVolNum := ErrorLevel
} else
MVolNum := 0

if Direct {
if (AVolNum - MP > MVolNum)
SetVolLv(AVolCNN, AVolNum - MP)
else ; MVolより音量が大きくなる場合
SetVolLv(AVolCNN, MVolNum)
} else {
SetVolLv(AVolCNN, AVolNum + MP)
}

VolLvView(AVolCNN, MVolCNN)
return
}

SetVolLv(AVolCNN, VolNum) {
ControlGet, AVolHwnd, Hwnd, , %AVolCNN%
SendMessage, 0x405, 0x1, %VolNum%, %AVolCNN% ; TBM_SETPOS

ParCNN := "#32770" RegExReplace(AVolCNN, "^msctls_trackbar32(\d+)$", "$1")
ControlGet, ParHwnd, Hwnd, , %ParCNN%
if ParHwnd
SendMessage, 0x115, 0x4,%AVolHwnd%, , ahk_id %ParHwnd% ; WM_VSCROLL
else
SendMessage, 0x115, 0x4,%AVolHwnd% ; WM_VSCROLL
}

VolFocusMove(Direct = 1) {
MVolNN := GetMVolNN()

ControlGetFocus, AVolCNN
if !RegExMatch(AVolCNN, "^(msctls_trackbar32|ToolbarWindow32)(\d+)$", $) {
ControlFocus, msctls_trackbar32%MVolNN%
return
}
if ("msctls_trackbar32" == $1)
AVolNN := $2
else
AVolNN := $2 // 2

if Direct {
if (MVolNN == AVolNN++)
TrgVolCNN := "msctls_trackbar321"
else
TrgVolCNN := "msctls_trackbar32" AVolNN
} else {
if (1 == AVolNN--)
TrgVolCNN := "msctls_trackbar32" MVolNN
else
TrgVolCNN := "msctls_trackbar32" AVolNN
}
ControlFocus, %TrgVolCNN%

VolLvView(TrgVolCNN, "msctls_trackbar32" MVolNN)
}

GetMVolNN() {
WinGet, CList, ControlList, 音量ミキサー ahk_class #32770
MVolNN := 0
Loop, Parse, CList, `n
if RegExMatch(A_LoopField, "^msctls_trackbar32(\d+)$", $)
if (MVolNN < $1)
MVolNN := $1
return MVolNN
}

VolLvView(AVolCNN, MVolCNN) {
SendMessage 0x400, , , %AVolCNN% ; TBM_GETPOS
AVolNum := ErrorLevel
AVolLv := 100 - AVolNum
SendMessage 0x400, , , %MVolCNN% ; TBM_GETPOS
MVolLv := 100 - ErrorLevel

WinGetTitle, AWTitle
TitleBuf := RegExReplace(AWTitle, "(.*?) Vol:[\d/ ]+?$", "$1") " Vol:" MVolLv

LoopCnt := RegExReplace(MVolCNN, "^msctls_trackbar32(\d+)$", "$1") - 1
Loop, %LoopCnt% {
SendMessage, 0x400, , , msctls_trackbar32%A_Index% ; TBM_GETPOS
TitleBuf .= " / " 100 - ErrorLevel
}
WinSetTitle, %TitleBuf%

ControlGetPos, CX, CY, , CH, %AVolCNN%
TY := CY + (CH - 24) / 100 * AVolNum - 24
ToolTip, Vol:%AVolLv% / %MVolLv%, %CX%, %TY%, 10 ; ToolTip番号は適当に

SetTimer, VolLvCheck, 100
}

VolLvCheck:
IfWinNotActive, 音量ミキサー ahk_class #32770
ToolTip, , , , 10 ; ToolTip番号は適当に
IfWinNotExist, 音量ミキサー ahk_class #32770
SetTimer, VolLvCheck, Off
return

 以前も書いたが、音量ミキサーのソフトウェアごとの音量は絶対値でなく、マスターボリュームに対する割合にした方がいいと思ってるのだが、ひとまず満足したんでやめた。

 正直、ソフトウェア側でなくOS側で音量いじることってあまりないが、まあAHKでトラックバー(スライドバー)いじる練習になったからいいかな……。

c0031643_20503090.png

TODO:実用上問題ないが、微妙なところがあるので機能強化のついでに直す。来週。直した


[PR]
# by lordnoesis | 2013-12-06 20:43 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、Link Shell Extensionを使ってリパースポイントを相対パスで作り直す。

 親フォルダをリネームしただけで、絶対パスで作ってあったシンボリックリンクが死んだので、相対パスで作り直そうと思ったのだけど、数が多くて面倒なのでAHKスクリプト書いた。

 自前でリパースポイントいじるにはDeviceIoControl叩く必要があるらしく面倒なので、「Link Shell Extension」が拡張するプロパティ項目を利用する。

;--------------------------------------------------------------------------------------
; WindowsExplorer
;--------------------------------------------------------------------------------------
#IfWinActive, ahk_class CabinetWClass

!l::  ; 選択したリパースポイントを相対パスに
  KeyWait, l
  KeyWait, alt
  
  SetTitleMatchMode, Slow
  
  CurPath := RegExEscape(GetCurPath())
  
  PathList := GetSelectItemPath()
  Loop, Parse, PathList, `n, `r%A_Space%"
  {
    Run, AutoHotkeyU64 _Script\FilePropertyOpen.ahk %A_LoopField%
    SplitPath, A_LoopField, FileName, DirName
    
    WinWaitActive, %FileName%のプロパティ ahk_class #32770, %DirName%
    Loop
    {
      Control, TabRight , 1, SysTabControl321
      WinGetText, WinTxt
      IfInString, WinTxt, リンクの種類
        break
    }
    ControlGetText, CtrlTxt, Edit2
    CtrlTxt2 := RegExReplace(CtrlTxt, CurPath "[^\\]*\\", ".\")
    if (CtrlTxt2 != CtrlTxt)
      ControlSetText, Edit2, %CtrlTxt2%
    Sleep, 50
    Send, {Enter}
  }
return

GetCurPath(DQSW = 0) {  ; アクティブなエクスプローラのパス。
  WinGetText, CurPath, A
  RegExMatch(CurPath, "([A-Z]:\\[^\r\n]+)", $)
  if DQSW
    return """" $1 """"
  else
    return $1
}

GetSelectItemPath(DQSW = 0, FldSW = 0, ParseStr = "`n") {  ; エクスプローラで選択中のアイテムのパス。AutoHotkey スレッド part11 >>913
  for Window in ComObjCreate("Shell.Application").Windows
    if (Window.hwnd == WinExist()) {
      for Item in Window.Document.SelectedItems
      {
        if (FldSW && !Item.IsFolder)
          continue
        if DQSW
          FileList .= """" Item.Path """" ParseStr
        else
          FileList .= Item.Path ParseStr
        Cnt++
      }
      break
    }
  ErrorLevel := Cnt
  return, SubStr(FileList, 1, -1)
}

RegExEscape(StrBuf) {  ;正規表現で特別な文字を回避。
  EscList := "
(
\
.
*
?
+
[
{
}
|
(
`)
^
$
)"
  
  Loop, Parse, EscList, `n
    StringReplace, StrBuf, StrBuf, %A_LoopField%, \%A_LoopField%, All
  
  return, StrBuf
}

;--------------------------------------------------------------------------------------
; FilePropertyOpen.ahk
;  渡されたファイルのプロパティを開く。
;--------------------------------------------------------------------------------------

  SetTitleMatchMode, 3
  SetTitleMatchMode, Slow
  
  Loop, %0%
    Cmdline .= %A_Index% " "
  Cmdline := SubStr(Cmdline, 1, -1)
  
  RunWait, properties %Cmdline%
  SplitPath, Cmdline, FileName, DirName
  
  WinWait, %FileName%のプロパティ ahk_class #32770, %DirName%
  WinWaitClose
  
ExitApp

 エクスプローラでジャンクション/シンボリックリンクを選択してAlt+Lすると、現在表示しているフォルダを起点とした相対パスでリンクを作り直す。ただし「../」には非対応。

 AHKは32bit版を使っているため、64bit版Link Shell Extensionのプロパティ項目を開くのに、わざわざ64bit版AHKでFilePropertyOpen.ahkを実行する仕組みなので、Runのパスに注意。普通に開けるのなら、そのように。


[PR]
# by lordnoesis | 2013-10-20 22:31 | テクノロジ | Trackback | Comments(0)

AutoHotKeyで、MoniMoniを少し便利に。

 モニタの表示内容をウィンドウで確認できる、MoniMoniというソフトがある。例えば、セカンダリモニタの内容を表示したMoniMoniをプライマリモニタに配置しておけば、本物のセカンダリモニタを確認する必要がなくなる(その逆も可)。サブモニタの電源がOFFだったり、視認できない配置だったり、グラフィックチップはマルチモニタ対応だけどモニタがない環境などで活躍するんじゃないかなぁ。

 で。ワシの使い方だと、操作する時だけセカンダリモニタを確認できればよかったので、カーソルをセカンダリモニタに移動した時だけMoniMoniを表示するAHKスクリプト書いた。

;--------------------------------------------------------------------------------------
; MoniMoni
;--------------------------------------------------------------------------------------
#IfWinActive MoniMoni ahk_class #32770

!2::
  WinGetPos, , , WW, WH, MoniMoni ahk_class #32770
  ControlGetPos, , , CW, CH, Magnifier1, MoniMoni ahk_class #32770
  SysGet, Mnt2, Monitor, 2
  
  MoveW := Mnt2Right - Mnt2Left + WW - CW
  MoveH := Mnt2Bottom - Mnt2Top + WH - CH
  MoveX := A_ScreenWidth / 2 - MoveW / 2
  MoveY := A_ScreenHeight / 2 - MoveH / 2
  WinMove, MoniMoni ahk_class #32770, , MoveX, MoveY, MoveW, MoveH
  ControlClick, Button2, Operation ahk_class #32770
  
  SetTimer, MoniMoniActivate, 500
return

MoniMoniActivate:
  IfWinNotExist, MoniMoni ahk_class #32770
  {
    SetTimer, MoniMoniActivate, Off
    return
  }
  CoordMode, Mouse
  MouseGetPos, MX, MY
  if (0 <= MX) && (MX < A_ScreenWidth) && (0 <= MY) && (MY < A_ScreenHeight) {  ; Mnt1
    if MMASW {
      MMASW := 0
      WinMinimize
    }
  } else {
    if !MMASW {  ; Mnt2
      MMASW := 1
      WinActivate
    }
  }
return

 MoniMoniがアクティブの状態でAlt+2を押すと、セカンダリモニタの解像度に合わせてMoniMoniをリサイズし、カーソルの監視を始める。以後MoniMoniを終了するまで、セカンダリモニタに移動した時はMoniMoniをアクティブにし、プライマリモニタに移動した時はMoniMoniを最小化する。

OrangeMaker > MoniMoni


[PR]
# by lordnoesis | 2013-09-02 20:52 | テクノロジ | Trackback | Comments(0)

AutoHotKeyのダブルクォーテーションのエスケープ。

 ググってもChr(0s22)使えとしか出てこないのだが、""で行ける。
 例えば次のコードは、期待通りに動く。

F12::
  foo := "<a href=""../index.html"">"
  MsgBox, %foo%
return

 この情報、どこで知ったんだっけ?と思って探したら普通に書いてあったー。

AutoHotkey Wiki > #EscapeChar


[PR]
# by lordnoesis | 2013-08-29 19:32 | テクノロジ | Trackback | Comments(0)

AutoHotKeyで、AzPainter2を少し便利に。

 AzPainter2を少し便利にするスクリプト作った。今回実現したのはキー操作によるカレントレイヤの切り替えと、17段階の明度切り替え。

 カーソル上下でレイヤ切り替え。スクロールには非対応。ごくまれにレイヤ順が乱れることがあるが、気にしない方向で。発動時にカーソル動かすとレイヤ移動になっちゃうので、BlockInput入れた。解除されない場合、Alt+Ctrl+Deleteで強制解除できる。AzDには標準でカレントレイヤ切り替えあるのになー。

 PgUp、PgDnで明度変更。厳密にいうとHSVモードだと明度だが、RGBモードだと青。一度実行するとAzP2が終了するまで常駐するが、常駐時はスポイト等で明度を変更しても自動的に17段階のいずれかに補正される。
 こんなんなにに使うのかというと、Seeneon用の深度マップを作るのにめっちゃ便利。17段階(-8 ~ 0 ~ +8)なのも、中央(128)が欲しかったから。

;--------------------------------------------------------------------------------------
; AzPainter2
;--------------------------------------------------------------------------------------
#IfWinActive AzPainter2 - ahk_class Main

Numpad0::Space  ; Numpad0でもスクロール

Up::  ; ひとつ上をカレントレイヤに
  ALayerChange(1)
return

Down::  ; ひとつ下をカレントレイヤに
  ALayerChange(0)
return

PGUP::
.::  ; HSVモード時、明度を上げる(17段階)
  if (CVLv < 16)
    CVLv++
  C3SetLevel(CVLv)
return

PGDN::
,::  ; HSVモード時、明度を下げる(17段階)
  if (CVLv > 0)
    CVLv--
  C3SetLevel(CVLv)
return

ALayerChange(SW) {
  IfWinNotExist, レイヤ ahk_class Layer
    return
  
  BlockInput, On
  WinGetPos, WX, WY
  ControlGetPos, CX, CY, CW, CH, LayerView1
  CX += 4,   CY -= 16
  BaseX := WX + CX,   BaseY := WY + CY
  MaxX := BaseX + CW,   MaxY := BaseY + CH

  CoordMode, Pixel
  PixelSearch, , PY, BaseX, BaseY, MaxX, MaxY, 0xC6D1FF, 0, Fast
  if ErrorLevel {
    BlockInput, Off
    return
  }
  
  LayerNum := (PY - BaseY) // 35 + 1
  
  SW ? LayerNum-- : LayerNum++
  CCY := CY + 35 * LayerNum
  ControlClick, X%CX% Y%CCY%, , , L, 1, Pos NA
  BlockInput, Off
}

CheckCV:
  IfWinNotExist, AzPainter2 - ahk_class Main
  {
    ToolTip, , , , 2
    SetTimer, CheckCV, Off
    return
  }
  
  ControlGetText, CVNum, Edit3, コントロール ahk_class #32770
  if (BefCVNum == CVNum)
    return
  BefCVNum := CVNum
  
  CVLv := CVNum // 16
  if (8 <= (CVNum - CVLv * 16))
    CVLv++
  
  C3SetLevel(CVLv)
return

C3SetLevel(CVLv) {
  IfWinNotExist, コントロール ahk_class #32770
    return

  CoordMode, ToolTip
  WinGetPos, WX, WY
  ShowCVLv := CVLv - 8
  ToolTip, %ShowCVLv%, %WX%, %WY%, 2
  SetTimer, CheckCV, 300
  
  CVNum := 16 * CVLv
  ControlSetText, Edit3, %CVNum%
}

 レイヤの数は限られてるんだし、PixelSearchで広範囲を走査するより、その数だけPixelGetColorした方が早いんじゃね?と思ったが、そんなことはなかったぜ!
 あと、PixelSearchってFastがデフォじゃないんだな。他のコマンドはデフォが高速側な印象。


[PR]
# by lordnoesis | 2013-07-16 19:24 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、引数を動作中のソフトに渡すツール作った。ver.2.1.0

 S2WAは、あらかじめAppListを用意しておき、リスト内のソフトが起動済みならそのソフトに、そうでなければリストの一番上のソフトに、自身が受け取った引数を丸投げするツール。
 例えばいくつかのブラウザを使い分けている環境で、HTTPなどをS2WAに関連付けておけば、リンクを踏んだ時起動済みのブラウザで開かれるため、無駄にブラウザを起動せずに済む。

 ver.2.1.0では、OperaNext15が妙なディレクトリ構成なので、それに対応すべくAppListで正規表現を使えるようにした。

; ////////////////////////////////////////////////////////////////////////////////
;
; S2WA.ahk ver.2.1.0
;
; ////////////////////////////////////////////////////////////////////////////////

  FileEncoding, CP1200

  IfNotExist, %A_ScriptDir%\AppList.txt
  {
    MsgBox, %A_ScriptDir%\AppList.txt が存在しません!
    ExitApp
  }

  for process in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process")
    if process.ExecutablePath
      ProcessList .= process.ExecutablePath "`n"

  TrgExe := ""
  Loop, Read, %A_ScriptDir%\AppList.txt
  {
    if !A_LoopReadLine
      continue
    
    StringLeft, CharBuf, A_LoopReadLine, 1
    if ("*" == CharBuf)
      StringTrimLeft, SearchExe, A_LoopReadLine, 1
    else {
      StringReplace, SearchExe, A_LoopReadLine, \, \\, All
      StringReplace, SearchExe, SearchExe, ., \., All
      StringReplace, SearchExe, SearchExe, [, \[, All
      StringReplace, SearchExe, SearchExe, ], \], All
      StringReplace, SearchExe, SearchExe, +, \+, All
      StringReplace, SearchExe, SearchExe, {, \{, All
      StringReplace, SearchExe, SearchExe, }, \}, All
      StringReplace, SearchExe, SearchExe, ^, \^, All
      StringReplace, SearchExe, SearchExe, $, \$, All
      StringReplace, SearchExe, SearchExe, (, \(, All
      StringReplace, SearchExe, SearchExe, ), \), All
    }
    
    if RegExMatch(ProcessList, "im`n)^(" SearchExe ")$", $) {
      MsgBox, %$1%
      TrgExe := $1
      break
    }
  }

  If !TrgExe
    FileReadLine, TrgExe, %A_ScriptDir%\AppList.txt, 1

  Loop, %0%
  {
    CmdlineBuf := %A_Index%
    Run, %TrgExe% "%CmdlineBuf%"
    Sleep, 1000
  }

 使用するには、スクリプトと同じディレクトリにAppList.txtを用意し、S2WAを呼び出すだけ。S2WAはAppListを上から順に起動済みプロセスと照合し、いずれもHitしなければ一番上のソフトを起動する。

 AppListの仕様は以下の通り。

  • 文字コードはUnicode(UTF-16LE)。
  • 1行につきひとつのフルパス。
  • 行が*から始まった場合、その行は正規表現とみなされる。

 ただし、1行目は正規表現であってはならない。OperaNext15を最優先にしたいなら、以下のように記述する。

R:\Opera Next\launcher.exe
*R:\\Opera Next\\.*\\opera\.exe

 WindowsVista以降、httpなどのプロトコルへの関連付けは面倒になっている。詳しくはver.2.0.0の記事参照。


[PR]
# by lordnoesis | 2013-06-20 17:57 | Trackback | Comments(0)

OperaNext15を試して、Chrome拡張入れてみた。

 Opera15(以下OPR)のOperaNextが出たので色々いじってみた。なおOperaNextというのは、Operaの次期バージョンのプレビュー版であり、αとかβとかウィークリービルドのたぐいであって、間違っても正式版ではないので注意。

 OPRでは、エンジンがWebKit(Blink)へと変更になるが、スタッフが「Operaらしさはそのまま」といってたもんだから、ワシは「Opera in Webkit」的なものが出てくると思っていた。だがそこに「Chromium Opera Edition」としかいいようがないものが出てきたせいで、ワシのみならず、Operaクラスタは阿鼻叫喚と化したのだった。そのあとでスタッフが「不安定な機能はまだ実装してないだけ」「高速リリース採用するので、いずれOperaらしくなるよ!」などと弁明したため、現状は様子見である。
 などといきなりdisり気味だが、現時点でもChromeの代替としては十分であり、ワシはサブとして使っていたChromeを捨てた! OPRが真にOperaの代替となるまでは、メインはOpera12が続投すればいいじゃない!

 で。OPRでは拡張機能もWebKitの物を使うことになる。Operaの拡張ストアにOPRでアクセスするとOPR対応版だけが表示されるが、その数はまだ多くはない。そこで、OPR拡張がないならChrome拡張を使えばいいじゃない!というのが本題である(前置き長ぇ。

 Download Chrome Extensionを導入することで、普通にChromeストアから拡張をインストールできる。

 普通にChromeのストアに行っても、OPRでは「Chromeに追加」が表示されないので、手動でインストールせねばならない。
 まず、crxファイルをDLする。crxはhttp://clients2.google.com/service/update2/crx?response=redirect&x=id%3D%26uc%26lang%3Den-US&prod=chromeで、IDをはさんだURLで入手できる。IDは拡張の個別ページのURLに含まれている、32文字くらいのアスキー文字列。例えばLastPassのhttps://chrome.google.com/webstore/detail/lastpass/hdokiejnpimakedhajhdlcegeplioahdならhdokiejnpimakedhajhdlcegeplioahdがそうなので、crxのURLはhttp://clients2.google.com/service/update2/crx?response=redirect&x=id%3Dhdokiejnpimakedhajhdlcegeplioahd%26uc%26lang%3Den-US&prod=chromeとなる。OPRで入力しても「Operaのストアじゃないからダメ」といわれるだけなので、IEなどで適当なフォルダに保存する。
 あとは野良拡張と同じ。OPRの拡張管理画面にドロップすると一覧に追加され確認が出るので、吹き出しの「インストール」を押せばおk。

 Opera Next 16では、opera://flags内のDynamic extension toolbar scalingを有効にすることで、アイコンの表示数を増やすことができるが、ウィンドウ幅依存なので表示しきれない可能性がある。

 ただし注意点がいくつかある。OPRの拡張バーは現状、最初の6個までしかアイコンを表示できない。非表示でも拡張自体は有効だが、アクセス手段がアイコンしかない場合は実質、利用不可能となる。アイコンの並び順=インストール順なので、アイコン必須の拡張からインストールし、一時的にアイコンが必要になった場合に上位の拡張を無効化するなどの工夫が必要となる。

 以下、試してみたよさげな拡張。

OPRストア


LastPass -- バージョン情報に「Chrome版」とある。
AdBlock

Chromeストア


はてなブックマーク GoogleChrome 拡張
Tab Manager -- タブ一覧。ファビコンのみ、あるいはファビコンとタイトル。
Tabs Outliner -- タブ一覧。ファビコンとタイトル。ポップアップでなく別ウィンドウ。OPRに未実装の「ウィンドウ間でのタブ移動」が可能。
Tab Expose -- タブ一覧。サムネイル。
theTabs -- タブ一覧。サムネイル。ポップアップでなく独立タブ。ひとつめのウィンドウのみ。
Zoom Text Only -- テキストのみ拡縮。ショートカットキーによる動作だが、設定はアイコンからしかできない。
PageRank -- Googleウェブ履歴にちゃんとタイトルが残る物の中で、シンプルなやつ。
AutoPatchWork
ToggleLink: Select Text From Link -- リンク上でshiftを叩くとただの文字列になる。5秒で元に戻る。


[PR]
# by lordnoesis | 2013-06-01 13:30 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、EverythingSearchのカラムとウィンドウ幅を自動調整してみた。

 一般的なListView等には「Ctrl+NumpadAdd(テンキーのプラス)」でカラム(列)幅の自動調整を行うショートカットが存在するらしく、Everythingも例外ではない。だが当然ながらこの機能はカラム幅を変更するだけで、ウィンドウサイズはそのままだ。ゆえに、普段はウィンドウを小さくしている場合、面倒なことになる。
 Everythingの1.3βにはウィンドウサイズの変更ショートカットがあり、「自動」もあるのだが、この機能はマルチモニタ環境を考慮しないため、ひとつのモニタに収まりきらない可能性がある。そもそも二回もショートカット使うというのがスマートでない。自動化すべきである。

 というわけで、Everything上でCtrl+NumpadAddすると、カラム幅を自動調節したのち、それがすべて見渡せるようにウィンドウ幅も自動調節する(ウィンドウのあるモニタ幅が上限)AHKスクリプト書いた。少し変えればEverything以外にも使えるかも?

;--------------------------------------------------------------------------------------
; Everything
;--------------------------------------------------------------------------------------
#IfWinActive ahk_class ahk_class EVERYTHING

$^NumpadAdd::
  ACtrl :=
  while ("EVERYTHING_LISTVIEW1" != ACtrl) {
    ControlFocus, EVERYTHING_LISTVIEW1
    ControlGetFocus, ACtrl
  }
  Send, ^{NumpadAdd}
F12::
  WinGetPos, WinX, WinY, WinW, WinH
  WinYC := WinH // 2 + WinY, WinXC := WinW // 2 + WinX
  MntNum := 2  ; 有効なモニタ数(頻繁に変更するなら↓をアンコメント)
  ;~ SysGet, MntNum, 80
  Loop, %MntNum%
  {
    SysGet, Mnt, MonitorWorkArea, %A_Index%
    if (MntTop < WinYC) && (WinYC < MntBottom) && (MntLeft < WinXC) && (WinXC < MntRight)
      break
  }
  if (MntLeft < WinX)
    AftWinX := WinX
  else
    AftWinX := MntLeft
  AftWinW := MntRight - AftWinX
  
  Sleep, 50
  SysGet, FW, 32
  SysGet, VSW, 2
  ControlGet, Hwnd, Hwnd, , EVERYTHING_LISTVIEW1
  GetScrollInfoAll(Hwnd, SB_HORZ, , nMax)
  AftWinW2 := nMax + VSW + FW * 2 + 1
  if (AftWinW > AftWinW2)
    AftWinW := AftWinW2
  
  WinMove, , , %AftWinX%, , %AftWinW%
return

; https://sites.google.com/site/agkh6mze/strage 窓調査.ahk
GetScrollInfoAll(hwnd, type, ByRef nMin="", ByRef nMax="", ByRef nPage="", ByRef nPos="", ByRef nTrackPos="") {
    VarSetCapacity(SCROLLINFO, 7*4, 0x00)
    NumPut(28, SCROLLINFO, 0, "Int")
    NumPut(0x17, SCROLLINFO, 4, "Int") ; SIF_RANGE & SIF_PAGE & SIF_POS & SIF_TRACKPOS = 0x17
    nMin:="", nMax:="", nPage:="", nPos:="", nTrackPos:=""
    if (!DllCall("user32.dll\GetScrollInfo", "UInt", hwnd, "Int",type, "Ptr", &SCROLLINFO, "Int"))
      Return false
    nMin := NumGet(SCROLLINFO, 8, "Int")
    nMax := NumGet(SCROLLINFO, 12, "Int")
    nPage := NumGet(SCROLLINFO, 16, "Int")
    nPos := NumGet(SCROLLINFO, 20, "Int")
    nTrackPos := NumGet(SCROLLINFO, 24, "Int")
    Return true
}

 横スクロールバーの範囲を取得して、ウィンドウサイズをそれ+縦スクロールバーの幅に拡縮してるだけ。

 たまにちゃんと働かんことがあるのだが、何度か繰り返す運用でカバー。


[PR]
# by lordnoesis | 2013-05-21 19:41 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、Operaの起動を便利にしてみた。 ver.2.3.0

 AutoHotKey_Lで、Operaの起動を便利にしてみた。をちょっと強化。AutoSave.winをブックマークに変換する際に、スタックごとにフォルダで分ける機能の追加。あと小規模改善。

; --------- --------- --------- --------- ---------
; RunOpera.ahk ver.2.3.0
; --------- --------- --------- --------- ---------

#WinActivateForce

  OperaPath := "R:\Opera"  ; Opera.exeの存在するパス。末尾"\"は不可。
  
  if %0%  ; 引数があった場合、Operaのパスと見なす
    OperaPath = %1%
  
  SessionsPath := OperaPath "\profile\sessions"  ; セッションフォルダのフルパスを指定。末尾"\"は不可。
  BookmarksPath := OperaPath "\profile\bookmarks.adr"  ; bookmarks.adrのフルパスを指定。
  
  TimeLimit := 30  ; 最終セッション退避確認ダイアログを自動でスキップするまでの秒数。
  
  AutoConvSW := 1  ; 最終セッションを退避させる場合、自動でブックマークに変換する設定。 0:変換しない。 1:変換する。
  ACMoveSW := 1  ; 自動変換(↑)したセッションを隔離する設定。 0:隔離しない。 1:隔離する。
  
  StackSW := 1  ; スタックの設定。 0:無視する。 1:スタックごとにフォルダを分ける。
  
  HisReadSW := 0  ; タブ履歴(タブで表示したページの履歴)の設定。 0:最新のみ読み込む。 1:すべて読み込む。
  His0PrefixSW := 0  ; タブ履歴がなかった場合のプレフィックスの設定。 0:なし。 1:0を明示する。
  
  WriteTrgSW := 1  ; ブックマーク情報を書き込む場所の設定。 0:セッションフォルダにテキストで保存。 1:bookmarks.adrに書き込む。
  
; --------- --------- --------- --------- ---------
  
  IfNotExist, %SessionsPath%\
  {
    MsgBox, 16, , セッションフォルダが見つかりません。`n%SessionsPath%
    ExitApp
  }
  If WriteTrgSW {
    IfNotExist, %BookmarksPath%
    {
      MsgBox, 16, , bookmarks.adrが見つかりません。`n%BookmarksPath%
      ExitApp
    }
  }
  
  IfNotExist, %SessionsPath%\autosave.win
  {
    IfExist, %SessionsPath%\autosave.win.bak
      FileMove, %SessionsPath%\autosave.win.bak, %SessionsPath%\autosave.win
  }
  IfExist, %SessionsPath%\autosave.win
  {
    FileCopy, %SessionsPath%\autosave_RunOpBak.win, %SessionsPath%\autosave_RunOpBak2.win, 1  ; ↓セッション退避etc.を実行しない時も念のため2世代バックアップ。
    FileCopy, %SessionsPath%\autosave.win, %SessionsPath%\autosave_RunOpBak.win, 1
    GoSub, SessionAnalyze
  }
  
  FileCopy, %OperaPath%\ui\fastforward_backup.ini, %OperaPath%\ui\fastforward.ini, 1  ; アップデートのたびにFastForward.iniが初期化される問題の対策。
  
  Run, %OperaPath%\opera.exe, , , OpPid
  WinWait, ahk_pid %OpPid%, , 60
  if !ErrorLevel {
    ifWinExist, Opera へようこそ ahk_pid %OpPid%
    {
      WinActivate
      WinWaitClose
    }
  } else {
    return
  }
  
  WinWait, マスターパスワードを入力してください ahk_pid %OpPid%, , 5
  If ErrorLevel
    return
  WinSet, Topmost, ON
  WinActivate
  Sleep, 300
  
ExitApp

; --------- --------- --------- --------- ---------

SessionAnalyze:
  FileRead, OSession, *P65001 *t %SessionsPath%\autosave.win
  If ErrorLevel {
    MsgBox, 48, , Sessionの読み込みに失敗しました。`n%SessionsPath%\autosave.win
    return
  }
  
  Idx := 0
  WinTitles := ""
  Loop {
    Idx := RegExMatch(OSession, "\[(\d+)history url\][\s\S]+?count=(\d+)", $, Idx + 1)
    If !Idx
      Break
    WinNum := $1
    HisNum := $2 - 1
    HisTitle := GetHisTitle(OSession, WinNum, HisNum, Idx)
    WinTitles .= " " HisTitle "`n"
  }
  If !WinTitles
    return
    
  SetTimer, RenewCount, 1000
  MsgBox, 259, 退避確認(30秒後に通常起動), 起動時に最終セッションを退避しますか?`n`n◆最終セッションの内容◆`n%WinTitles%, %TimeLimit%
  SetTimer, RenewCount, Off
  IfMsgBox, Yes
  {
    TimeNum := A_Now
    BackupName := TimeNum ".win"
    Loop {
      FileMove, %SessionsPath%\autosave.win, %SessionsPath%\%BackupName%
      If !ErrorLevel  ; 最終セッションのリネームに成功なら
        Break
      BackupName := TimeNum "_" A_Index ".win"
    }
    FileDelete, %SessionsPath%\autosave.win.bak
    If AutoConvSW
      GoSub, SessionConvert
  }
  IfMsgBox, Cancel
    ExitApp
return

; --------- --------- --------- --------- ---------

RenewCount:
  IfWinExist, 退避確認( ahk_class #32770
  {
    TimeLimit--
    WinSetTitle, 退避確認(%TimeLimit%秒後に通常起動)
    if !TimeLimit
      SetTimer, RenewCount, Off
  }
return

; --------- --------- --------- --------- ---------

SessionConvert:
  If WriteTrgSW
    FileCopy, %BookmarksPath%, %BookmarksPath%_%A_Now%  ; bookmarks.adrのバックアップは無制限なので注意
  
  CmdLine := SessionsPath "\" BackupName
  SplitPath, CmdLine, , , , SessionName
  Result := "#FOLDER`n  NAME=[Session] " SessionName "`n`n"
  ResultBuf := Result
  
  Idx := 0
  BefGroupNum := 0
  His0Prefix :=
  Loop {
    Idx := RegExMatch(OSession, "\[(\d+)\][\s\S]+?group=(\d+)[\s\S]+?\[\1history url\][\s\S]+?count=(\d+)", $, Idx + 1)
    If !Idx
      Break
    WinNum := $1
    GroupNum := $2
    HisNum := $3 - 1
    HisTitle := GetHisTitle(OSession, WinNum, HisNum, Idx)
    HisUrl := GetHisUrl(OSession, WinNum, HisNum, Idx)
    
    if StackSW
      if (BefGroupNum != GroupNum) {
        if BefGroupNum
          Result .= "-`n`n"
        if GroupNum
          Result .= "#FOLDER`n  NAME=[Stack] " GroupNum "`n`n"
        BefGroupNum := GroupNum
      }
    
    If !HisReadSW {  ; タブ履歴を無視する場合
      Result .= "#URL`n  NAME=" HisTitle "`n  URL=" HisUrl "`n`n"
      Continue
    }
    
    StringLen, HisNumLen, HisNum
    
    If !HisNum {
      if His0PrefixSW
        His0Prefix := "[" ZeroSupply(HisNum, HisNumLen) "] "
      Result .= "#URL`n  NAME=" HisPrefix HisTitle "`n  URL=" HisUrl "`n`n"
      Continue
    }
    Result .= "#FOLDER`n  NAME=" HisTitle "`n`n#URL`n  NAME=[" ZeroSupply(HisNum, HisNumLen) "] " HisTitle "`n  URL=" HisUrl "`n`n"
    
    Loop, %HisNum% {
      HisNum--
      HisTitle := GetHisTitle(OSession, WinNum, HisNum, Idx)
      HisUrl := GetHisUrl(OSession, WinNum, HisNum, Idx)
      Result .= "#URL`n  NAME=[" ZeroSupply(HisNum, HisNumLen) "] " HisTitle "`n  URL=" HisUrl "`n`n"
    }
    Result .= "-`n`n"
  }
  
  If (ResultBuf == Result)
    return
  Result .= "-`n`n"
  
  If WriteTrgSW {
    FileRead, BMBuf, *t *P65001 %BookmarksPath%
    StringGetPos, Idx, BMBuf, #DELETED
    if !Idx {
      StringMid, BMBufP, BMBuf, 1, Idx
      StringMid, BMBufS, BMBuf, Idx + 1
      Result := BMBufP Result BMBufS
      FileDelete, %BookmarksPath%
    }
    FileAppend, %Result%, %BookmarksPath%, CP65001
  } Else {
    FileDelete, %CmdLine%.txt
    FileAppend, %Result%, %CmdLine%.txt, CP65001
  }
  
  If ACMoveSW {
    IfNotExist, %SessionsPath%\AutoConv\
      FileCreateDir, %SessionsPath%\AutoConv\
    FileMove, %CmdLine%, %SessionsPath%\AutoConv\%BackupName%
    If ErrorLevel
      MsgBox, 48, , 変換済みセッションの移動に失敗しました。`n%SessionsPath%\AutoConv\
  }
return

; --------- --------- --------- --------- ---------

GetHisTitle(OSession, WinNum, HisNum, Idx){
  RegExMatch(OSession, "\[" WinNum "history title\][\s\S]+?" HisNum "=(.*?)\r?\n", $)
  return $1
}

GetHisUrl(OSession, WinNum, HisNum, Idx){
  RegExMatch(OSession, "\[" WinNum "history url\][\s\S]+?" HisNum "=(.*?)\r?\n", $)
  return $1
}

ZeroSupply(Num, NumDigit){
  StringLen, NumLen, Num
  LoopNum := NumDigit - NumLen
  Loop, %LoopNum%
    Num := 0 Num
  return, Num
}

セッション確認ダイアログ

c0031643_22274759.png

ブックマーク変換例。

c0031643_12534236.jpg


[PR]
# by lordnoesis | 2013-05-12 12:55 | テクノロジ | Trackback | Comments(0)

MultiPar同梱のpar2j.exeで任意のフォルダのリカバリファイルを作成するバッチ。

 あらかじめファイルを解析してリカバリファイル(Par形式)を作っておくことで、もしファイルが破損しても復元できるかもしれないMultiParというツールがある。リカバリファイルってのは、ファイルに対するパリティだとか、RAR書庫のリカバリレコードみたいなもんだと思っとけば、だいたいあってるんじゃないかな!

 Parは元々、転送エラー必至の通信環境でファイル転送を成功させるために作られたそうだが、耐用年数が気になる光学メディアや、S.M.A.R.T.が微妙に警告発してるようなHDDを使い続けなきゃならん環境とかでも大活躍だ。

 ただ、MultiParはGUIなんで、一括処理には向いてない。というわけで、同梱されてるCUIツール「par2j.exe」を使って、任意のフォルダのリカバリファイルを作成するバッチ書いた。

@echo off
echo ###########################################################################
echo #
echo # CreatePar2.bat
echo #
::   # MultiPar同梱の「par2j.exe」でフォルダのリカバリファイルを作成する。
::   #
::   # 引数なし:カレントフォルダ直下のフォルダを処理。
::   # 引数あり:引数のフォルダを処理。
::   #
echo ###########################################################################

if exist %1 goto arg
echo.
echo ### %cd% 直下のフォルダを処理します。 ###
echo.

for /d %%i in (*) do @call :create %%~si

goto end


:arg
for %%i in (%*) do (
cd /d %%~dpsi
echo.
echo ### %%i を処理します。 ###
echo.

@call :create %%~si
)


:end
pause
exit


:create
::↓Par2j.exeまでのフルパスにすべし。
par2j.exe c /sm16384 /sr100 /rr10 "%1\!rr10.par2" "%1\*"par2j.exe c /sr1000 /rr3 "%1\!sr1000rr3.par2" "%1\*"
exit /b

 正直、Parをぼんやりとしか理解してない輩が、英語ヘルプを機械翻訳してなんとなくで書いたのでry
 ブロック数多い方が(計算遅くなるが)、効率上がる(リカバリファイル小さくて済む)んだよ、な……? リカバリファイルは受け渡しするんでもなけりゃ、ひとつでもいいんだよな……?

 オプション変えてみた。

MultiPar -- 修復用データを作ってファイルの破損や消失に備える


[PR]
# by lordnoesis | 2013-02-18 22:17 | テクノロジ | Trackback | Comments(2)

AutoHotKeyで、ウィンドウを瞬間移動してみた(マルチモニタ対応)。

 ウィンドウを、いちいちマウスで移動するのが面倒だったので、アクティブなウィンドウを移動するAHK作った。
 デスクトップを3*3(右/中央/左、上/中/下)に区切って、ウィンドウを指定したデスクトップ淵に合わせる。マルチモニタ対応。

WinMoveG9(MntIdx = 0, MoveArea = 7) {
/*
 MntIdx : 異動先となるモニタ。デフォルトは0(移動しない)。
 MoveArea : 移動先となるグリッド(位置はテンキー参照)。デフォルトは7(左上)。
*/
  WinGet,WinId, ID, A
  WinGetPos, WinX, WinY, WinW, WinH, ahk_id %WinId%
  if MntIdx
    SysGet, Mnt, MonitorWorkArea, %MntIdx%
  else {
    WinYC := WinH // 2 + WinY, WinXC := WinW // 2 + WinX
    MntNum := 2 ; 有効なモニタ数(頻繁に変更するなら↓をアンコメント)
    ;~ SysGet, MntNum, 80
    Loop, %MntNum%
    {
      SysGet, Mnt, MonitorWorkArea, %A_Index%
      if (MntTop < WinYC) && (WinYC < MntBottom) && (MntLeft < WinXC) && (WinXC < MntRight)
        break
    }
  }

  if (7 == MoveArea || 4 == MoveArea || 1 == MoveArea)
    MoveX := MntLeft
  else if (8 == MoveArea || 5 == MoveArea || 2 == MoveArea)
    MoveX := (MntRight - MntLeft - WinW) / 2 + MntLeft
  else  ; if (9 == MoveArea || 6 == MoveArea || 3 == MoveArea)
    MoveX := MntRight - WinW

  if (7 == MoveArea || 8 == MoveArea || 9 == MoveArea)
    MoveY := MntTop
  else if (4 == MoveArea || 5 == MoveArea || 6 == MoveArea)
    MoveY := (MntBottom - MntTop - WinH) / 2 + MntTop
  else ; if (1 == MoveArea || 2 == MoveArea || 3 == MoveArea)
    MoveY := MntBottom - WinH

  WinMove, ahk_id %WinId%, , %MoveX%, %MoveY%
}

#Numpad1::WinMoveG9(0, 1)
#Numpad2::WinMoveG9(0, 2)
#Numpad3::WinMoveG9(0, 3)
#Numpad4::WinMoveG9(0, 4)
#Numpad5::WinMoveG9(0, 5)
#Numpad6::WinMoveG9(0, 6)
#Numpad7::WinMoveG9(0, 7)
#Numpad8::WinMoveG9(0, 8)
#Numpad9::WinMoveG9(0, 9)

#1::
  WinMoveG9(1)
return
#2::
  WinMoveG9(2)
return

#c::
  WinMoveG9(0, 5)
return

 例えば、Win+NumPad7で今いるモニタの基準位置(左上)に、Win+NumPad3なら今いるモニタの右下に移動。Win+NumPad5かWin+Cで画面中央に移動。Win+1でモニタ1の基準位置へ移動。


[PR]
# by lordnoesis | 2013-01-31 21:00 | Trackback | Comments(1)

AutoHotKey_Lで、Operaの起動を便利にしてみた。 ver.2.2.0

 AutoHotkey_Lで、Opera12の起動を便利にしてみた。をちょっと改善。状況によってセッション退避やブックマーク変換が機能しない問題とか直ったはず(ちょっとしたってレベルじゃねーぞ。

 作者にもわからんくなってきたので、機能をまとめてみる。

  • Operaの起動前に、前回終了時のセッション(AutoSave.win)の内容を確認できる。
  • AutoSave.winを復元せずに、空のOperaを起動することができる。
  • 復元しない場合、AutoSave.winをブックマークに変換できる。
  • AutoSave.winの2世代バックアップ。
  • FastForward_backup.iniでFastForward.iniを上書きする(アップデート対策)。
  • 起動直後に出現するマスターパスワード入力ダイアログを最前面固定かつアクティブにする。
 ――うん、地味!

; --------- --------- --------- --------- ---------
; RunOpera.ahk ver.2.2.0
; --------- --------- --------- --------- ---------

#WinActivateForce

  OperaPath := "R:\Opera"  ; Opera.exeの存在するパス。末尾"\"は不可。

  if %0%  ; 引数があった場合、Operaのパスと見なす
    OperaPath = %1%

  SessionsPath := OperaPath "\profile\sessions\"  ; セッションフォルダのフルパスを指定。末尾"\"は不可。
  BookmarksPath := OperaPath "\profile\bookmarks.adr"  ; bookmarks.adrのフルパスを指定。

  TimeLimit := 30  ; 最終セッション退避確認ダイアログを自動でスキップするまでの秒数。

  AutoConvSW := 1  ; 最終セッションを退避させる場合、自動でブックマークに変換する設定。 0:変換しない。 1:変換する。
  ACMoveSW := 1  ; 自動変換(↑)したセッションを隔離する設定。 0:隔離しない。 1:隔離する。

  HisReadSW := 0  ; タブ履歴(タブで表示したページの履歴)の設定。 0:最新のみ読み込む。 1:すべて読み込む。
  WriteTrgSW := 1  ; ブックマーク情報を書き込む場所の設定。 0:セッションフォルダにテキストで保存。 1:bookmarks.adrに書き込む。

; --------- --------- --------- --------- ---------

  IfNotExist, %SessionsPath%\
  {
    MsgBox, 16, , セッションフォルダが見つかりません。`n%SessionsPath%
    ExitApp
  }
  If WriteTrgSW {
    IfNotExist, %BookmarksPath%
    {
      MsgBox, 16, , bookmarks.adrが見つかりません。`n%BookmarksPath%
      ExitApp
    }
  }

  IfNotExist, %SessionsPath%\autosave.win
  {
    IfExist, %SessionsPath%\autosave.win.bak
      FileMove, %SessionsPath%\autosave.win.bak, %SessionsPath%\autosave.win
  }
  IfExist, %SessionsPath%\autosave.win
  {
    FileCopy, %SessionsPath%\autosave_RunOpBak.win, %SessionsPath%\autosave_RunOpBak2.win, 1  ; ↓セッション退避etc.を実行しない時も念のため2世代バックアップ。
    FileCopy, %SessionsPath%\autosave.win, %SessionsPath%\autosave_RunOpBak.win, 1
    GoSub, SessionAnalyze
  }

  FileCopy, %OperaPath%\ui\fastforward_backup.ini, %OperaPath%\ui\fastforward.ini, 1  ; アップデートのたびにFastForward.iniが初期化される問題の対策。

  Run, %OperaPath%\opera.exe, , , OpPid
  WinWait, ahk_pid %OpPid%, , 60
  if !ErrorLevel {
    ifWinExist, Opera へようこそ ahk_pid %OpPid%
    {
      WinActivate
      WinWaitClose
    }
  } else {
    return
  }

  WinWait, マスターパスワードを入力してください ahk_pid %OpPid%, , 5
  If ErrorLevel
    return
  WinSet, Topmost, ON
  WinActivate

ExitApp

; --------- --------- --------- --------- ---------

SessionAnalyze:
  FileRead, OSession, *P65001 *t %SessionsPath%\autosave.win
  If ErrorLevel {
    MsgBox, 48, , Sessionの読み込みに失敗しました。`n%SessionsPath%\autosave.win
    return
  }

  Idx := 0
  WinTitles := ""
  Loop {
    Idx := RegExMatch(OSession, "\[(\d+)history url\].+?count=(.*?)\n", $, Idx + 1)
    If !Idx
      Break
    WinNum := $1
    HisNum := $2 - 1
    HisTitle := GetHisTitle(OSession, WinNum, HisNum, Idx)
    WinTitles .= " " HisTitle "`n"
  }
  If !WinTitles
    return


  SetTimer, RenewCount, 1000
  MsgBox, 259, 退避確認(30秒後に通常起動), 起動時に最終セッションを退避しますか?`n`n◆最終セッションの内容◆`n%WinTitles%, %TimeLimit%
  SetTimer, RenewCount, Off
  IfMsgBox, Yes
  {
    TimeNum := A_Now
    BackupName := TimeNum ".win"
    Loop {
      FileMove, %SessionsPath%\autosave.win, %SessionsPath%\%BackupName%
      If !ErrorLevel  ; 最終セッションのリネームに成功なら
        Break
      BackupName := TimeNum "_" A_Index ".win"
    }
    FileDelete, %SessionsPath%\autosave.win.bak
    If AutoConvSW
      GoSub, SessionConvert
  }
  IfMsgBox, Cancel
    ExitApp
return

; --------- --------- --------- --------- ---------

RenewCount:
  IfWinExist, 退避確認( ahk_class #32770
  {
    TimeLimit--
    WinSetTitle, 退避確認(%TimeLimit%秒後に通常起動)
    if !TimeLimit
      SetTimer, RenewCount, Off
  }
return

; --------- --------- --------- --------- ---------

SessionConvert:
  If WriteTrgSW
    FileCopy, %BookmarksPath%, %BookmarksPath%_%A_Now%  ; bookmarks.adrのバックアップは無制限なので注意

  CmdLine := SessionsPath "\" BackupName
  SplitPath, CmdLine, , , , SessionName
  Result := "#FOLDER`n  NAME=[Session] " SessionName "`n`n"
  ResultBuf := Result

  Idx := 0
  Loop {
    Idx := RegExMatch(OSession, "\[(\d+)history url\].+?count=(.*?)\n", $, Idx + 1)
    If !Idx
      Break
    WinNum := $1
    HisNum := $2 - 1
    HisTitle := GetHisTitle(OSession, WinNum, HisNum, Idx)
    HisUrl := GetHisUrl(OSession, WinNum, HisNum, Idx)

    If !HisReadSW {  ; タブ履歴を無視する場合
      Result .= "#URL`n  NAME=" HisTitle "`n  URL=" HisUrl "`n`n"
      Continue
    }

    StringLen, HisNumLen, HisNum

    If !HisNum {
      Result .= "#URL`n  NAME=[" ZeroSupply(HisNum, HisNumLen) "] " HisTitle "`n  URL=" HisUrl "`n`n"
      Continue
    }
    Result .= "#FOLDER`n  NAME=" HisTitle "`n`n#URL`n  NAME=[" ZeroSupply(HisNum, HisNumLen) "] " HisTitle "`n  URL=" HisUrl "`n`n"

    Loop, %HisNum% {
      HisNum--
      HisTitle := GetHisTitle(OSession, WinNum, HisNum, Idx)
      HisUrl := GetHisUrl(OSession, WinNum, HisNum, Idx)
      Result .= "#URL`n  NAME=[" ZeroSupply(HisNum, HisNumLen) "] " HisTitle "`n  URL=" HisUrl "`n`n"
    }
    Result .= "-`n`n"
  }

  If (ResultBuf == Result)
    return
  Result .= "-`n`n"

  If WriteTrgSW {
    FileRead, BMBuf, *t *P65001 %BookmarksPath%
    StringGetPos, Idx, BMBuf, #DELETED
    if !Idx {
      StringMid, BMBufP, BMBuf, 1, Idx
      StringMid, BMBufS, BMBuf, Idx + 1
      Result := BMBufP Result BMBufS
      FileDelete, %BookmarksPath%
    }
    FileAppend, %Result%, %BookmarksPath%, CP65001
  } Else {
    FileDelete, %CmdLine%.txt
    FileAppend, %Result%, %CmdLine%.txt, CP65001
  }

  If ACMoveSW {
    IfNotExist, %SessionsPath%\AutoConv\
      FileCreateDir, %SessionsPath%\AutoConv\
    FileMove, %CmdLine%, %SessionsPath%\AutoConv\%BackupName%
    If ErrorLevel
      MsgBox, 48, , 変換済みセッションの移動に失敗しました。`n%SessionsPath%\AutoConv\
  }
return

; --------- --------- --------- --------- ---------

GetHisTitle(OSession, WinNum, HisNum, Idx){
  RegExMatch(OSession, "\[" WinNum "history title\].+?" HisNum "=(.*?)\n", $)
  return $1
}

GetHisUrl(OSession, WinNum, HisNum, Idx){
  RegExMatch(OSession, "\[" WinNum "history url\].+?" HisNum "=(.*?)\n", $)
  return $1
}

ZeroSupply(Num, NumDigit){
  StringLen, NumLen, Num
  LoopNum := NumDigit - NumLen
  Loop, %LoopNum%
    Num := 0 Num
  return, Num
}

 これまでとは逆に、OperaPath等は末尾\不可になったので注意。

セッション確認ダイアログ

c0031643_22274759.png

ブックマーク変換例(下側はHisReadSW := 1)。

c0031643_22281581.jpg


[PR]
# by lordnoesis | 2013-01-23 22:32 | テクノロジ | Trackback(1) | Comments(0)

AutoHotKey_Lで、フォルダの備忘録(あとで読む)作ってみた。

 私はタブが大好きなので、エクスプローラもタブ化している。そして、タブを開いていけばやがては「当面は必要ないから閉じたいけど、閉じると作業予定も忘れちゃうだろうなー」みたいなヤツが出てくる。これがブラウザだったら、いわゆる「あとで読む」のたぐいを使えばいいのだけど――というわけで作ったった!

 ウィンドウにドロップすると記録。リスト項目をダブルクリックで開く。その際、左端のチェックボックスが非チェックなら削除。右ダブルクリックすればチェックも無視して削除(開かない)。
 終了時にリストを記録して、次回起動時に再現。以上!

;/////////////////////////////////////////////////////////////////////////////////////
;
; OpenLater.ahk
;  フォルダをあとで開く
;
;/////////////////////////////////////////////////////////////////////////////////////


  DefCheckSW := 0  ; デフォルトで保護するか否か


;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


  if DefCheckSW
    DefCheckStr := "Check"
  
  FileEncoding, UTF-8-RAW
  
  SplitPath, A_ScriptName, , , , LogName
  LogPath := A_ScriptDir "\" LogName ".log"
  
  MarginX := 10, MarginY := 5
  Gui, Add, ListView, Checked AltSubmit Grid vPathListView gPathListViewAct, ID|名前|パス
  
  Loop, Read, %LogPath%
  {
    NowID := A_Index
    StringLeft, CheckSW, A_LoopReadLine, 1
    if CheckSW
      CheckStr := "Check"
    else
      CheckStr :=
    StringTrimLeft, DirPath, A_LoopReadLine, 1
    SplitPath, DirPath, DirName
    LV_Add("Vis " CheckStr, NowID, DirName, DirPath)
    StringReplace, DirPathEsc, DirPath, `,, `,`,, All
    PathList .= DirPathEsc ","
  }
  LV_ModifyCol(1, "Logical Auto")
  LV_ModifyCol(2, "Logical 100")
  LV_ModifyCol(3, "Logical AutoHdr")
  
  Gui, +AlwaysOnTop +Resize +MinSize
  Gui, Show, w300 h168
return

GuiDropFiles:
  GuiControl, -Redraw, PathListView

  StringReplace, DropList, A_GuiEvent, `r`n, `n, All
  NowID := LV_GetCount()
  Loop, Parse, DropList, `n, \
  {
    DirPath := A_LoopField
    FileAttrib := FileExist(DirPath)
    IfNotInString, FileAttrib, D
      continue
    StringReplace, DirPathEsc, DirPath, `,, `,`,, All
    if DirPathEsc in %PathList%
      continue
    PathList .= DirPathEsc ","
    SplitPath, DirPath, DirName
    NowID++
    LV_Add("Vis " DefCheckStr, NowID, DirName, DirPath)
  }
  gosub, ColWidthReset

  GuiControl, +Redraw, PathListView
return

PathListViewAct:
  if ("R" == A_GuiEvent)
    DelSW := 1
  else
    DelSW := 0
  
  if DelSW || ("A" == A_GuiEvent) {  ; 項目ダブクリ
    TrgItemID := A_EventInfo
    LV_GetText(DirPath, TrgItemID, 3)
    if !DelSW
      IfExist, %DirPath%
        Run, open %DirPath%
    if DelSW || (TrgItemID != LV_GetNext(TrgItemID - 1, "C")) {  ; 項目削除
      GuiControl, -Redraw, PathListView
      
      LV_GetText(DelPathID, TrgItemID, 1)
      StringReplace, DirPathEsc, DirPath, `,, `,`,, All
      StringReplace, PathList, PathList, %DirPathEsc%`,
      LV_Delete(TrgItemID)
      ListLineCnt := LV_GetCount()
      Loop, %ListLineCnt% {
        LV_GetText(PathID, A_Index, 1)
        if (PathID > DelPathID)
          LV_Modify(A_Index, "", PathID - 1)
      }
      gosub, ColWidthReset
      
      GuiControl, +Redraw, PathListView
    }
  }
return

ColWidthReset:
  LV_ModifyCol(1, "Auto")
  ;~ LV_ModifyCol(2, "100")
  LV_ModifyCol(3, "AutoHdr")
return

GuiSize:
  if (1 == A_EventInfo)
    return
  EMW := A_GuiWidth - MarginX * 2
  EMH := A_GuiHeight - MarginY * 2
  
  GuiControl, Move, PathListView, W%EMW% H%EMH%
  LV_ModifyCol(3, "Logical AutoHdr")
return

GuiClose:
  GuiControl, -Redraw, PathListView
  
  LV_ModifyCol(1, "Sort")
  PathList :=
  ListLineCnt := LV_GetCount()
  Loop, %ListLineCnt% {
    LV_GetText(DirPath, A_Index, 3)
    if (LV_GetNext(A_Index - 1, "C") == A_Index)
      PathList .= "1" DirPath "`n"
    else
      PathList .= "0" DirPath "`n"
  }
  FileDelete, %LogPath%
  FileAppend, %PathList%, %LogPath%
ExitApp

 Unicodeを諦めれば(FileEncodingをコメントアウト)、AHK_Lでなくともいいはず。

 以下はOpenLater.ahkを使いやすくする常駐スクリプト。エクスプローラでフォルダ(複数可)を選択してF11を押せばそのフォルダが、なにも選択していなければカレントフォルダがOpenLaterに送られる。
 OpenLaterが最小化状態でも問題なく動作する。

;--------------------------------------------------------------------------------------
; WindowsExplorer
;--------------------------------------------------------------------------------------
#IfWinActive, ahk_class CabinetWClass

$F11::
  KeyWait, F11
  PathList := GetSelectItemPath()
  if !ErrorLevel {
    WinGetText, CurPath, A
    RegExMatch(CurPath, "([A-Z]:\\[^\r\n]*)", $)
    PathList := $1
  }
  PathListEx :=
  Loop, Parse, PathList, `n
    IfExist, %A_LoopField%
      PathListEx .= A_LoopField "`n"
  Sort, PathListEx

  Sort, PathList
  IfWinNotExist, OpenLater.ahk ahk_class AutoHotkeyGUI
    Run, open hoge\OpenLater.ahk  ; OpenLater.ahkのパス
  WinWait, OpenLater.ahk ahk_class AutoHotkeyGUI
  WinGet, Hwnd, ID
  DropFiles(Hwnd, PathListEx)
  DropFiles(Hwnd, PathList)
return

GetSelectItemPath(FldSW = 0) {  ; AutoHotkey スレッド part11 >>913
  for Window in ComObjCreate("Shell.Application").Windows
    if (Window.hwnd == WinExist()) {
      for Item in Window.Document.SelectedItems
      {
        if (FldSW && !Item.IsFolder)
          continue
        FileList .= Item.Path "`n"
        Cnt++
      }
      break
    }
  StringTrimRight, FileList, FileList, 1
  ErrorLevel := Cnt
  return, FileList
}

DropFiles(hwnd, files, ptX=0, ptY=0, fNC=False) {  ; AutoHotkey スレッド part11 >>332
  static char_type:= A_IsUnicode ? "UShort" : "UChar"
    , char_size := A_IsUnicode ? 2 : 1
    , isUnicode := A_IsUnicode ? 1 : 0
  files := RTrim(files, "`r`n`t ") . "`n`n"
  byte_length := StrLen(files) * char_size
  Loop, Parse, files
    If (A_LoopField = "`n")
      NumPut(0x00, files, (A_Index-1) * char_size, char_type)
  
  hDrop := DllCall("GlobalAlloc", "UInt", 0x42, "UInt",20 + byte_length, "Ptr")
  p := DllCall("GlobalLock", "Ptr", hDrop)
  NumPut(20 , p + 00, "Int") ; offset
  NumPut(ptX , p + 04, "Int") ; pt.x
  NumPut(ptY , p + 08, "Int") ; pt.y
  NumPut(fNC , p + 12, "Int") ; fNC
  NumPut(isUnicode, p + 16, "Int") ; fWide
  DllCall("RtlMoveMemory", "Ptr", p + 20, "Str", files, "UInt", byte_length)
  DllCall("GlobalUnlock", "Ptr", hDrop)
  PostMessage, WM_DROPFILES := 0x233, hDrop , 0, , ahk_id %hwnd%
}

 DropFiles()のあとにウィンドウを閉じてもよさげ。

c0031643_1355170.png


[PR]
# by lordnoesis | 2012-12-13 22:38 | テクノロジ | Trackback | Comments(0)

AutoHotKeyで、Everythingの検索結果からEverythingを呼び出してみた。

 EverythingSearchの検索結果で項目を選択してF4を押すと、選択項目のパスを新しいウィンドウ(仮名「結果ウィンドウ」)で検索するAHKスクリプト。Explorerなどでも便利なので、適当に#IfWinActiveをいじってやってみよう!(手抜き)
 「結果ウィンドウ」は、可能な限り再利用される。ただし「結果ウィンドウ」で実行した場合は、さらに新たなウィンドウが呼び出され、今後はそちらが再利用対象になる。

 Everythingでフォルダパスを検索(=フォルダを選択してF4)した場合、結果はそのフォルダ以下のファイル一覧。ファイルパスを検索(=ファイルを選択してF4)した場合、結果はそのファイルのみ。
 フォルダパスでフォルダの中身を検索したり、ファイルパスを削って「同じフォルダの別のファイル」や「別フォルダの同じ名前のファイル」を検索したり、あるいは「F4を二度押して(ファイルのみのウィンドウを残して)、一時的なファイル備忘録として使う」など、可能性は無限大だ!

  EverythingPath := "C:\Program Files (x86)\Everything\Everything.exe"  ; Appごとに似て非なるルーチンがたくさんあるので、AutoExecuteセクションで変数に格納してる。

;--------------------------------------------------------------------------------------
; Everything
;--------------------------------------------------------------------------------------
#IfWinActive ahk_class ahk_class EVERYTHING

$F4::
  Send, ^c
  sleep, 200
  SearchWord := Clipboard

;  if RegExMatch(SearchWord, "適当に整形すればいいと思うよ!",$)
;    SearchWord := $1

  WinGet, HwndA, ID, A
  if (WinExist("ahk_id " HwndEV " ahk_class EVERYTHING") && (HwndA != HwndEV)) {
    ControlSetText, Edit1, %SearchWord%
    WinActivate
  } else {
    Run, %EverythingPath% -search "%SearchWord%"
    Loop {
      WinGet, HwndEV, ID, %SearchWord% ahk_class EVERYTHING
      if (HwndEV && (HwndEV != HwndA))
        break
      Sleep, 200
    }
  }
  WinWaitActive, ahk_id %HwndEV%
  ControlSend, EVERYTHING_LISTVIEW1, ^{NumpadAdd}  ; カラム幅自動調整
return

 WinGet, OutputVar, MinMaxで、「結果ウィンドウ」を最大化してるウィンドウに固定しても便利。最大化したら他が見えない? AeroSnapや半画面化を使うんだ!

 気づいたこと。

  • WinExist関数の対象もLastFoundWindowになるぽ? 日本語リファレンスには記載ない。
  • ExcludeTitleって文字列以外(ahk_idとか)は使えないのかー。
  • Ctrl+NumpadAddはフォーカス箇所で動作が変わる。文字欄ならEverythingの「文字拡大」、SysListView32では標準の「カラム幅自動調整」。


[PR]
# by lordnoesis | 2012-11-30 22:12 | テクノロジ | Trackback | Comments(0)
ブログトップ | ファンになる