カテゴリ:テクノロジ( 199 )

AutoHotKey_Lで、OperaのRamDisk運用を便利にしたかった……。

 前回の更新直後に「コピーのタイミングってWindowsの起動/終了時でいいんじゃ……」と遅まきながら気づいてしまい、レストア/バックアップ機能だけ取り出し強化したのだが、結局、「バッチでXCOPY使えばいい」の域を出られなかった残念なAHKスクリプト。

 一応、起動時にOperaをRamDiskにコピーし、Opera終了時/Windows終了時には自動でバックアップしてくれる。――のだが、バックアップ対象を絞らないと30秒ほどかかるので、レジストリで「応答のないアプリケーションを自動で終了する」をONにしてると間に合わない。

 グループポリシーが使える環境の人は、シャットダウンスクリプトでXCOPY使うのが正解。でなければ、RamDiskを自動バックアップ対応のものに変えれ。

; --------- --------- --------- --------- ---------
;
; CopyOpera.ahk
;
; ・起動時にOperaをRamDiskにコピー(レストア)する。
; ・常駐中はOperaを監視し、隙あらばHDDにコピー(バックアップ)する。
;  ・Operaが終了した時や、Windowsが終了する時など。
; ・指定フォルダの除外コピーが可能(cacheフォルダやmailフォルダなど)
;
; --------- --------- --------- --------- ---------

#Persistent

  OperaPath := "C:\Program Files\Opera\Opera"  ; Opera.exeの存在するフルパスを指定。
  RamPath := "R:\Opera"  ; Operaのコピー先となるフルパスを指定。

  NGPathR := "profile\cache | profile\icons | profile\mail | profile\opcache | profile\temporary_downloads"  ; レストアしないディレクトリをOperaPathからの相対パスで指定
  NGPathB := NGPathR  ; バックアップしないディレクトリを、RamPathからの相対パスで指定

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

  OperaPath := CutLastDelimiter(OperaPath), RamPath := CutLastDelimiter(RamPath)
  NGPathR := ConvList(NGPathR), NGPathB := ConvList(NGPathB)

  OpBackupSW := 0

  gosub, OpRestore

  SplashView("OperaReady!")

  OnExit, ExitOp
  SetTimer, CheckOp, 5000
return

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

ExitOp:
  if OpBackupSW {
    Process, WaitClose, opera.exe
    gosub, OpBackup
    SplashView("OperaBackup!")
    Sleep, 3000
  }
ExitApp

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

CheckOp:
  Cnt++
  if (30 < Cnt) {
    Cnt := 0
    FileCopy, %RamPath%\profile\sessions\autosave.win, %OperaPath%\profile\sessions\autosave.win, 1
  }

  Process, WaitClose, opera.exe, 1
  if (0 == ErrorLevel) { ; Operaが動いていなければ
    if OpBackupSW {  ; まだバックアップされていなければ
      gosub, OpBackup
      SplashView("OperaBackup!")
      OpBackupSW := 0
    }
  } else{  ; Operaが動いていれば
    OpBackupSW := 1
  }
return

OpRestore:
  DirList := DigDirList(OperaPath, OperaPath, NGPathR)
  DirSet(RamPath, DirList)
  DirListCopy(DirList, OperaPath, RamPath)
return

OpBackup:
  DirList := DigDirList(RamPath, RamPath, NGPathB)
  DirSet(OperaPath, DirList)
  DirListCopy(DirList, RamPath, OperaPath)
return

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

ConvList(FileList) {
  Res := ""
  Loop, Parse, FileList, |, %A_Space% \
  {
    if ("" == A_LoopField)
      continue
    FieldBuf := CutLastDelimiter(A_LoopField)
    result := result FieldBuf "`n"
  }
  return, CutLastNL(result)
}

GetDirList(TrgDir, RootPath , NGList) {
  if ("" == TrgDir)
    return
  result := ""
  LoopPattern := RootPath "\" CutRootPath(TrgDir, RootPath) "\*"
  Loop, %LoopPattern%, 2, 0
  {
    GetDir := CutRootPath(A_LoopFileLongPath, RootPath)
    if !NGCheck(GetDir, NGList) 
      result := result GetDir "`n"
  }
  return, CutLastNL(result)
}

DigDirList(TrgPath, RootPath, NGList) {
  DirList := "`n"
  TrgDirList := GetDirList(TrgPath, RootPath, NGList) "`n"
  ResDirList := ""
  Loop {
    Loop, Parse, TrgDirList, `n
    {
      ResDir := GetDirList(A_LoopField, RootPath, NGList)
      if ("" != ResDir)
        ResDirList := ResDirlist ResDir "`n"
    }
    DirList := DirList TrgDirList
    TrgDirList := ResDirList
    ResDirList := ""
    if ("" == TrgDirList)
      break
  }
  return, CutLastNL(DirList)
}

DirSet(TrgPath, DirList) {
  Loop, Parse, DirList, `n
    FileCreateDir, %TrgPath%\%A_LoopField%
  return
}

DirListCopy(DirList, RootPath, SendPath) {
  Loop, Parse, DirList, `n
    FileCopy, %RootPath%\%A_LoopField%\*, %SendPath%\%A_LoopField%, 1
  return
}

NGCheck(Keyword, NGList) {
  Loop, Parse, NGList, `n
  {
    if (1 == RegExMatch(Keyword, "s)^" EscRegEx(A_LoopField)))
      return, 1
  }
  return, "0"
}

CutLastDelimiter(TrgPath) {
  StringRight, CharBuf, TrgPath, 1
  if ("\" == CharBuf)
    StringTrimRight, TrgPath, TrgPath, 1
  return, TrgPath
}

CutLastNL(TrgPath) {
  result := RegExReplace(TrgPath, "s)[\r\n]+\z", "", $, 1)
  return, Result
}

CutRootPath(TrgPath, RootPath) {
  return, RegExReplace(TrgPath, "s)^" EscRegEx(RootPath) "(\\)?", "", $, 1)
}

EscRegEx(trg) {
  EscList := "\`n.`n*`n?`n+`n[`n]`n{`n}`n|`n(`n)`n^`n$"
  Loop, Parse, EscList, `n
    StringReplace, trg, trg, %A_LoopField%, \%A_LoopField%, 1
  return, trg
}

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

SplashView(TextBuf, Timer = 3000) {
  Progress, B1 ZH0 W800, %TextBuf%
  SetTimer, SplashClose, %Timer%
}

SplashClose:
  SetTimer, SplashClose, Off
  Progress, Off
return

 下位フォルダをいじるスクリプトに流用できるから、無駄死にではないぞ。ま、負け惜しみじゃないんだからっ。

 PCの突然死対策に、2分半に一度、autosave.winだけバックアップするようにしてみた。というか使うだけならバックアップするのこれだけでよさげ。


[PR]
by lordnoesis | 2012-04-16 22:39 | テクノロジ | Trackback | Comments(0)

AutoHotkey_Lで、Operaの起動と終了を便利にしてみた。

 RamDiskを少しでも活用しようとOperaのキャッシュフォルダを配置して(速度向上は体感できなかったが、HDD寿命的に)満足してたのだが、TL眺めてたら「RamdiskにOpera置いたら爆速」とあって、試してみたら速度向上したので、RunOpera.ahkに組み込んでみた。

 RamDisk起動機能を有効にすると、OperaをRamDiskにコピーして起動し、終了したら元のフォルダにコピーする。監視対象はRunOpera.ahkから起動したOperaのみ。Operaを起動させたままWindowsを終了した場合、Operaが終了するまで待機して元フォルダにコピーしてから終了する……ハズ。
 基本的な使い方は前回を参照。実は他にも地味に機能が増えてるが、普通に使う分には大差ないので省略。

; --------- --------- --------- --------- ---------
; RunOpera.ahk
; --------- --------- --------- --------- ---------

#WinActivateForce

  OperaPath := "C:\Program Files\Opera\Opera\"  ; Opera.exeの存在するパスを指定。末尾は"\"。

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

  RamPath := "R:\Opera\"  ; RamDisk起動時に、Operaのコピー先となるフルパスを指定。末尾は"\"。

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

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

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

  RamCopySW := 0  ; RamDisk起動の設定。 0:通常起動。 1:コピーして起動し、終了したら書き戻す。
      ; ※ RamDisk起動を利用する場合、Operaはスタンドアロン版であること。

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

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

  IfExist, %SessionsPath%autosave.win
    GoSub, SessionAnalyze

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

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

  Process, WaitClose, opera.exe, 60  ; ↓終了させたはずのOperaがゾンビ化してないか確認。
  if ErrorLevel {
    MsgBox, 16, , Operaはすでに起動しています。
    ExitApp
  }

  if RamCopySW {  ; RamCopySWが1なら
    FileCopyDir, %OperaPath%, %RamPath%, 1
    OnExit, ExitOp
    SetTimer, CheckOp, -1000
    RunWait, %RamPath%opera.exe, , , OpPid
  } else {  ; RamCopySWが0なら通常起動
    Run, %OperaPath%opera.exe, , , OpPid
    gosub, CheckOp
  }

ExitApp

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

ExitOp:
  Process, WaitClose, %OpPid%
  FileCopyDir, %RamPath%, %OperaPath%, 1
ExitApp

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

CheckOp:
  WinWait, ahk_pid %OpPid%, , 60
  if !ErrorLevel {
    ifWinExist, Opera へようこそ ahk_pid %OpPid%
    {
      WinActivate
      WinWaitClose
    }
  } else {
    return
  }

  WinWait, パスワード ahk_pid %OpPid%, , 5
  If ErrorLevel
    return

  WinActivate
  Sleep, 300
return

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

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

  Idx := 0
  WinTitles := ""
  Loop {
    Idx := RegExMatch(OSession, "\[(\d+)history url\].+?count=(.*?)\n", $, Idx + 1)
    If (0 == Idx)
      Break
    WinNum := $1
    HisNum := $2 - 1
    HisTitle := GetHisTitle(OSession, WinNum, HisNum, Idx)
    WinTitles := 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(0 == ErrorLevel)
        Break
      BackupName := TimeNum "_" A_Index ".win"
    }
    If (1 == AutoConvSW)
      GoSub, SessionConvert
  }
  IfMsgBox, Cancel
    Exit

Return

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

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

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

SessionConvert:
  If (1 == WriteTrgSW)
    FileCopy, %BookmarksPath%, %BookmarksPath%_%A_Now%

  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 (0 == Idx)
      Break
    WinNum := $1
    HisNum := $2 - 1

    HisTitle := GetHisTitle(OSession, WinNum, HisNum, Idx)
    HisUrl := GetHisUrl(OSession, WinNum, HisNum, Idx)

    If (0 == HisReadSW) {  ; タブ履歴を無視する場合
      Result .= "%uRL`n  NAME=" HisTitle "`n  URL=" HisUrl "`n`n"
      Continue
    }

    StringLen, HisNumLen, HisNum

    If (0 == 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 (1 == WriteTrgSW) {
    FileAppend, %Result%, %BookmarksPath%, CP65001
  } Else {
    FileDelete, %CmdLine%.txt
    FileAppend, %Result%, %CmdLine%.txt, CP65001
  }

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

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

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

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

ZeroSupply(Num, Digit){
  StringLen, NumLen, Num
  LoopNum := Digit - NumLen
  Loop, %LoopNum%
    Num := "0" Num
  Return, Num
}

 ひょっとしたら、タイミングによってはコピーが不完全なんてことも、ないとは言い切れないので、注意。

 RamDisk全体をバックアップ/レストアするだけでよくね?という正論は受け付けてません><


[PR]
by lordnoesis | 2012-04-15 18:28 | テクノロジ | Trackback | Comments(0)

auのJAVA対応ケータイにOpera Miniを入れてみた。

 auのオープンアプリ/Ezアプリ(J)対応機種でOpera Miniを使う方法の備忘録。公式訪れるだけじゃ入れられないとか、そのままじゃQVGAで見難く醜いとか、入れても通信エラーが多発するといった、いくつかある壁の解決方法。Opera Miniに限らず、野良アプリのインストールに応用できる。
 Opera Miniの魅力は改めて説明するまでもないので割愛。知らない人は公式サイトに行ってみよう!


Opera Miniの準備

 まず、OperaのOpera Mini & Opera MobileからOpera Miniをダウンロード。対象環境がカッコ書きされていないものがJ2ME版。今回は「Opera Mini 6.5」を選択し、言語選択で「日本語」を選んでからjadとjarを保存する。
  Opera Mini 7.0リリースされたけど、CA007だと設定が保存されたり、されなかったりだなぁ。6.5のままでいいような。でも7.0はページ描画の高速化がウリのひとつなんだよなー。

 次に、jadの編集。といっても、テキストエディタで開きOAP-Screen-Size: WVGAと書き加えるだけ。機種がWVGA非対応の場合は適当に。詳しくは、auの公式資料(後述)を参照。なお、公式資料には「jadはUTF-8」とあるが、おそらく罠。s-jisでないと失敗した。

Opera Miniの公開

 次に、用意したjad jarをwebで公開する。jad対応アップローダーを利用する手もあるが、今回は04WebServerでサーバーを立てた。04WSは、個人用途であれば十二分。
 設定は適当に。MIMEタイプの設定だけは必須。「サーバ設定 > MIMEタイプの設定」を開き、text/vnd.sun.j2me.app-descriptorjadapplication/Java-archivejarの二行を加える。コメントに「右がMIME、左が拡張子」とあるがこれは誤り。
 次に、htmlを用意してjadへのリンクを張る。リンクは<a href="device:jam?http://example.com/opera-mini-6.5.26955-advanced-ja.jad">Opera Mini</a>のような書式で、jadへの絶対パスを書く。パスも適当に。

Opera Miniのインストール

 次に、ケータイの標準ブラウザ(not PCSV)でこのリンクを踏み、インストールを行う。これまでの作業に問題がなければインストールは完了する。

 最後に、Opera Mini上で「メニューキー > Oメニュー > 設定」を開いて設定を行う。オープンアプリ/Ezアプリ(J)は「同時接続数は1」という制限があるので、Opera Linkは基本的に使えない。また、「Socket非対応」なので「詳細設定」からプロトコルを「http」のみにしておく(しなくても自動で判断するが)。

 一応、簡単な使い方を説明しておくと、Opera Miniは方向キーでカーソルを動かす他に、「8462キーで大きく移動」「5で拡大」、「#や*に続けていずれかのキーでショートカット」という操作がある。ショートカットについては「メニューキー > Oメニュー > ヘルプ > ショートカット」から確認可能。


 適切な解像度で運用するOpera Miniの美しく、便利なことよ。まさにOpera最強現実

 はじめ、接続エラーが多発して困ってたのだが、同時接続数1なのにOpera Linkが接続してるのが原因の模様。どうしてもOL使いたい人は、OLが同期してる間は我慢するしかない。

 ちなみに、アプリはSDカードからインストールも可能なのだが(PRIVATE/AU_INOUT/OAP/にjad jarを配置し、「Ezアプリ設定 > SD内アプリ一覧」)、Operaは上手くいかんかった。成功するアプリもあるが、差がわからん。OAP-Backupあたりが関係してる?

KDDI au: 技術情報 > EZアプリ(J)


[PR]
by lordnoesis | 2012-04-06 21:21 | テクノロジ | Trackback | Comments(0)

AutoHotKeyで、X-アプリ for LISMOをちょっと便利にしてみた。

 ウォークマンやauケータイの転送ソフトであるX-アプリで、ファイルをドロップするたびに「取り込み完了」とモーダルダイアログが出るのが邪魔だったので、監視してOKを押すだけのAHKスクリプト。

;----------------------------------------------------------------------------------------
; LismoCheck.ahk
;----------------------------------------------------------------------------------------

  SetTimer, LismoCheck, 1000
  MsgBox, Lismo監視中`n`nOKを押すと終了
  ExitApp

LismoCheck:
  IfWinExist,  x-アプリ for LISMO ahk_class #32770
  {
    WinGetText, WinTxt
    if ("OK`r`nファイルの取り込みが終了しました。`r`n" == WinTxt) {
      ControlClick, Button1
      WinTxt := ""
    }
  }
return

 これがフリーソフトなら、設定で変えられそうな機能なんだがなあ。見逃してるのかなぁ……。


[PR]
by lordnoesis | 2012-03-27 20:21 | テクノロジ | Trackback | Comments(0)

AutoHotKeyで、Windowsデスクトップガジェットを一時非表示にできるようにしてみた。

 Windows7では自由に配置できるようになったデスクトップガジェットだが、操作の邪魔になる状況もちらほら。最前面にして常時表示しておきたいんだけど、それだとガジェットで隠れて操作できない――みたいな。
 というわけで、マウスカーソルがデスクトップガジェットにホバーしている間だけ、デスクトップガジェットを非表示にするAHKスクリプト。――標準でついてるべき機能なんじゃねーの!?

;////////////////////////////////////////////////////////////////////////////////
;
; WindowsDesktopGadgetAvoid.ahk ver.1.1.0
;
;////////////////////////////////////////////////////////////////////////////////

  CoordMode, Mouse, Screen
  SetTimer, WGadgetCheck, 500

$#g::
  SetTimer, WGadgetCheck, Off
  SetTimer, WGadgetRestore, Off
  GroupAdd, WGadget, ahk_class SideBar_HTMLHostWindow
  WinShow, ahk_group WGadget
  Send, #g
  Sleep, 3000
  Reload
return

WGadgetCheck:
  if GetKeyState("Shift") || GetKeyState("Ctrl") || GetKeyState("Alt")
    return
  MouseGetPos, mX, mY, mHWND
  WinGetClass, mClass, ahk_id %mHWND%
  if ("SideBar_HTMLHostWindow" == mClass) {
    WG_Num := 1
    Loop {
      WinGet, WG_HWND, ID, ahk_class BasicWindow
      if ("" == WG_HWND)
        break
      WinGetPos, wX, wY, wW, wH, ahk_id %WG_HWND%
      if (0 < wW) && (0 < wH) {
        GroupAdd, WGadget, ahk_id %WG_HWND%
        WinHide, ahk_id %WG_HWND%
        Win%WG_Num%X := wX, Win%WG_Num%Y := wY, Win%WG_Num%X2 := wX + wW, Win%WG_Num%Y2 := wY + wH
        WG_Num++
      }
    }
    SetTimer, WGadgetRestore, 2000
    SetTimer, WGadgetCheck, Off
  }
return

WGadgetRestore:
  MouseGetPos, mX, mY
  WG_Hover := 0
  Loop, %WG_Num% {
    wX := Win%A_Index%X
    wX2 := Win%A_Index%X2
    wY := Win%A_Index%Y
    wY2 := Win%A_Index%Y2
    if (wX <= mX) && (mX <= wX2) && (wY <= mY) && (mY <= wY2) {
      WG_Hover := 1
      break
    }
  }
  if !WG_Hover {
    WinShow, ahk_group WGadget
    SetTimer, WGadgetCheck, 500
    SetTimer, WGadgetRestore, Off
  }
return

 影のあるガジェット(標準の「時計」など)は影が残ったりするけど実用上問題ないので仕様。
 よく見たらクラス名ついてたので対応。

 修飾キーを押している間は非表示にしないように。

 デスクトップガジェットをマウスで操作したい場合、タスクトレイからスクリプトを停止させるか、Win+Gで3秒ほど停止するのでその間に。

 Win+Gってのは、ガジェットをアクティブにする標準のホットキーなので、「最前面にある必要はないけどたまに見たい」って人は活用すべし。たとえばMG2.ahkで、カーソルを画面端に移動させるとWin+G出すようにするなど。


[PR]
by lordnoesis | 2012-03-12 21:44 | テクノロジ | Trackback | Comments(0)

AutoHotkey_Lで、Operaの起動を便利にしてみた。

 以前書いたOpera用AHKスクリプトの「起動時に最終セッションを退避」に「セッションをブックマークに変換」を合わせてみた。あと細かいミスも修正。

 このスクリプトを実行すると、Operaの最終(前回終了時の)セッションのタイトル一覧が表示され、セッションを退避するか問われる。YESにすると、セッションを現在日時で変名し、空のOperaが起動する。また、退避する場合、自動でセッションの内容をブックマークに変換することも可能。
 「前回、大量にタブ開いたまま終了したから起動がおっくうだなー」とか「最終セッション全部は必要ないなー」という場合に便利。自動変換に興味ない旧runOpera.ahkユーザーも、文字化けがなくなったので更新する価値はある、ような。

 使うには、以下のコードを適当に保存し、「SessionsPath」と「BookmarksPath」を埋めれば、最低限OK。初期設定ではセッションは自動変換されないし、bookmarks.adrへの書き込みも行われないので、安全を確認してから好みの設定にするよろし。
 書くべきパスはopera:about参照のこと。SessionsPathはファイル名いらないので注意。

 パスの確認を最初に行うように変更。失敗しても実害ないし、そもパス間違えるやつなんていないだろHAHAHA、と思っていたら、試験で存在しないパス入れたままなのを忘れてry

; --------- --------- --------- --------- ---------
; RunOpera.ahk
; --------- --------- --------- --------- ---------

#WinActivateForce

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

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

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

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

  IfNotExist, %SessionsPath%
  {
    MsgBox, 48, セッションフォルダが見つかりません。`n%SessionsPath%
    Exit
  }
  If (1 == WriteTrgSW) {
    IfNotExist, %BookmarksPath%
    {
      MsgBox, 48, bookmarks.adrが見つかりません。`n%BookmarksPath%
      Exit
    }
  }

  IfExist, %SessionsPath%autosave.win
    GoSub, SessionAnalyze

  Run, C:\Program Files\Opera\Opera\opera.exe, , , OpPid
  OpTitle := "パスワード"
  WinWait, %OpTitle% ahk_pid %OpPid%, , 60
  If(0 != ErrorLevel)
    Exit
  WinActivate
  Sleep, 500
Exit

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

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

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

  MsgBox, 259, 30秒後に通常起動します。, 起動時に最終セッションを退避しますか?`n`n◆最終セッションの内容◆`n%WinTitles%, 30
  IfMsgBox, Yes
  {
    TimeNum := A_Now
    BackupName := TimeNum ".win"
    Loop {
      FileMove, %SessionsPath%autosave.win, %SessionsPath%%BackupName%
      If(0 == ErrorLevel)
        Break
      BackupName := TimeNum "_" A_Index ".win"
    }
    If (1 == AutoConvSW)
      GoSub, SessionConvert
  }
  IfMsgBox, Cancel
    Exit
Return

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

SessionConvert:
  If (1 == WriteTrgSW)
    FileCopy, %BookmarksPath%, %BookmarksPath%_%A_Now%

  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 (0 == Idx)
      Break
    WinNum := $1
    HisNum := $2 - 1

    HisTitle := GetHisTitle(OSession, WinNum, HisNum, Idx)
    HisUrl := GetHisUrl(OSession, WinNum, HisNum, Idx)

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

    StringLen, HisNumLen, HisNum

    If (0 == 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 (1 == WriteTrgSW) {
    FileAppend, %Result%, %BookmarksPath%, CP65001
  } Else {
    FileDelete, %CmdLine%.txt
    FileAppend, %Result%, %CmdLine%.txt, CP65001
  }

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

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

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

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

ZeroSupply(Num, Digit){
  StringLen, NumLen, Num
  LoopNum := Digit - NumLen
  Loop, %LoopNum%
    Num := "0" Num
  Return, Num
}

 余談だが、SnakeCaseもPascalCaseもCamelCaseもしっくりこなくて困る。いやPascalCaseでおおむね問題ないのだが、ifとかloopとかreturnみたいな単語が大文字だと違和感が。慣れか。


[PR]
by lordnoesis | 2012-02-09 19:25 | テクノロジ | Trackback | Comments(0)

AutoHotKeyで「音量ミキサー」を呼び出して最大化してみた。

 WindowsVista以降、アプリケーションごとに音量を指定できるようになり、それにあわせてボリュームコントロールも「音量ミキサー」として生まれ変わったのだが、これが実に使いにくい。開いた直後は3つのアプリケーションしか表示できない程度の大きさで、しかもウィンドウを広げても記憶しない。

 まあ要するにウィンドウサイズいじるのを自動化すればいいだけなので、AHKでやってみた。

#V::
  run, SndVol.exe
  winWait, 音量ミキサー, , 10
  if (1 == errorLevel)
    return
  winGetPos, , , , WH
  winMove, , , 0, A_ScreenHeight - WH, A_ScreenWidth
return

 スクリプト呼び出すなり、ホットキー割り当てるなり、適当に。

 話は変わるが、音量ミキサーの最大の問題は、ボリューム指定の方法。ボリュームには大きく分けて音声デバイスのボリュームと、アプリケーション毎のボリュームがあって、例えばデバイスを増減させた時はアプリケーションの方は割合で増減する(デバイスを100→50にした時、appAは100→50、appBは50→25)。一方、アプリケーションをデバイスより上げると、デバイスも一緒に上がるが、ほかのアプリケーションのボリュームはそのまま。なにこれ。
 こんなややこしい挙動にするなら、アプリケーションのボリュームの方は最初から「現状の音量に対する割合」にすればよかったのに。


[PR]
by lordnoesis | 2012-01-31 17:57 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、Operaのセッションをブックマークに書き込んでみた。

 Operaのセッションを解析してブックマークに書き込むスクリプト。bookmarks.adrの仕様が不明瞭だったので、とりあえずテキストに書き出したのが前回。だがつい先日、実は最低限必要なのはNAMEとURLだけ(他はOperaの起動時に補完される)と知り、さっそくやってみた。

 以下のスクリプトを適当に保存し、"bookmarks.adr"のフルパスを書き込んだら準備完了。あとはセッションファイルを引数にして呼び出す(ドロップ可。複数ファイル対応)と、ブックマークに変換される。その後、Operaを起動すると数秒ののち、"[Session] セッションファイル名"というフォルダにセッションの内容が!

 ちょっといじって、スクリプト冒頭で挙動設定を可能にしてみた。デフォルトだと「タブ履歴無視」「プレーンテキストで保存」なので、いじってみるよろし。bookmarks.adrの指定も忘れないように。

; -------- --------- --------- --------- ---------
; OperaSession2Bookmarks.ahk
; -------- --------- --------- --------- ---------
  BookmarksPath := "C:\Program Files\Opera Next\profile\bookmarks.adr"  ; bookmarks.adrのフルパスを指定。
  HisSW := 0  ; タブの履歴(そのタブで表示したページの履歴)をどうするかの設定。 0:最後に表示したアドレスのみ読み込む。 1:すべて読み込む。
  WriteSW := 0  ; 書き込み先の設定。 0:セッションと同じ位置にプレーンテキストで保存。 1:bookmarks.adrに書き込む。

  If (1 == WriteSW) {
    IfNotExist, %BookmarksPath%
    {
      MsgBox, %BookmarksPath%が見つかりません。
      Exit
    }
    FileCopy, %BookmarksPath%, %BookmarksPath%_%A_Now%
  }

  Loop, %0%
  {
    CmdLineBuf := %A_Index%
    Loop %CmdLineBuf%, 1
      CmdLine := A_LoopFileLongPath
    FileRead, OSession, *P65001 *t %CmdLine%
    If (ErrorLevel) {
      MsgBox, Session File Read Error
      Exit
    }

    SplitPath, CmdLine, , , , SessionName
    Result := "#FOLDER`n  NAME=[Session] " SessionName "`n`n"
    Header := Result
    Idx := 0

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

      RegExMatch(OSession, "\[" WinNum "history title\].+?" HisNum "=(.*?)\n", $)
      HisTitle := $1
      RegExMatch(OSession, "\[" WinNum "history url\].+?" HisNum "=(.*?)\n", $)
      HisUrl := $1

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

      If (0 == 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--
        RegExMatch(OSession, "\[" WinNum "history title\].+?" HisNum "=(.*?)\n", $)
        HisTitle := $1
        RegExMatch(OSession, "\[" WinNum "history url\].+?" HisNum "=(.*?)\n", $)
        HisUrl := $1
        Result .= "#URL`n  NAME=[" ZeroSupply(HisNum, HisNumLen) "] " HisTitle "`n  URL=" HisUrl "`n`n"
      }
      Result .= "-`n`n"
    }

    If (Header == Result)
      Continue
    Result .= "-`n`n"

    If (1 == WriteSW) {
      FileAppend, %Result%, %BookmarksPath%, CP65001  ; bookmarks.adrに直接書き込む
    } Else {
      FileDelete, %CmdLine%.txt  ; ↓のファイルがすでに存在していたら削除(やらないと追記)
      FileAppend, %Result%, %CmdLine%.txt, CP65001  ; セッションと同じ位置に書き出す
    }
  }
  MsgBox, Finish!
Return

ZeroSupply(Num, Digit){
  StringLen, NumLen, Num
  LoopNum := Digit - NumLen
  Loop, %LoopNum%
    Num := "0" Num
  Return, Num
}

 これで大量のタブを気軽に記録できる。あと、OperaLinkでセッション(だったもの)が共有できる副作用も。
 まさにすべてのOpera-erへの福音(えー。


[PR]
by lordnoesis | 2012-01-10 20:32 | テクノロジ | Trackback | Comments(0)

MouseGesture.ahkでウィンドウ操作メニュー表示してみた。2

 リリース直後に即更新。前回のは実はα版だったんだよ!!! Ω ΩΩ {後付け乙。

 というわけで、ウィンドウ操作メニューを表示するMouseGesture2用スクリプトver.1.0.1。

  • 変更点
    • メニュー呼び出しを「タイトルバー右側のボタンを右クリック」で行うように変更。
    • 操作対象をアクティブウィンドウではなく、右クリックしたウィンドウに変更。
    • 入れ忘れてた最前面固定を追加。

 まず、ソース内のコメントに従い以下のスクリプトを導入。3箇所あるので注意。

; -------- --------- --------- --------- ---------
; 以下を"MG_User.ahk"の初期化処理セクションに追加。
; -------- --------- --------- --------- ---------

MenuId_Max := 0, ItemId := 0, HieLv := 0
MenuId_Cur := "WH" MenuId_Max
Menu, WH0, Add, 最前面, WH_Topmost
Menu, WH0, Add
Loop,Read, WinHack.txt
{
  RegExMatch(A_LoopReadLine, "^\s?([\[\]\;]|----)?\s?([^,]*)\s*,?\s*([^,]*)\s*,?\s*([^,]*)\s*,?\s*([^,]*)\s*,?\s*([^,]*)", $)
  if(";" == $1)
    Continue
  ItemId++
  if("[" == $1) {
    MenuId_HL%HieLv% := MenuId_Cur
    MenuId_Max++
    MenuId_Cur := "WH" MenuId_Max
    %MenuId_Cur%_Text := $2
    ItemId_HL%HieLv% := ItemId
    ItemId := 0
    HieLv++
    Continue
  }
  if("]" == $1) {
    HieLv--
    MenuId_HLUpp := MenuId_HL%HieLv%
    MenuId_Cur_Text := %MenuId_Cur%_Text
    Menu, %MenuId_HLUpp%, Add, %MenuId_Cur_Text%, :%MenuId_Cur%
    MenuId_Cur := MenuId_HLUpp
    ItemId := ItemId_HL%HieLv%
    Continue
  }
  WM_X%MenuId_Cur%_%ItemId% := $3
  WM_Y%MenuId_Cur%_%ItemId% := $4
  WM_W%MenuId_Cur%_%ItemId% := $5
  WM_H%MenuId_Cur%_%ItemId% := $6
  Menu, %MenuId_Cur%, Add, %$2%, WH_WM
}
Menu, WH0, Add
Menu, WH_WK, Add, 実行, WH_WK
Menu, WH_Etc, Add, 強制終了, :WH_WK
Menu, WH_Etc, Add, プログラムのフォルダを開く(&O), WH_AppDirOpen
Menu, WH_Etc, Add
Menu, WH_Etc, Add, WinHack.txtを開く, WH_SettingOpen
Menu, WH0, Add, その他, :WH_Etc


; -------- --------- --------- --------- ---------
; 以下を"MG_User.ahk"のサブルーチン定義セクションに追加。
; -------- --------- --------- --------- ---------

WH_Show:
  WinGet, state, ExStyle, ahk_id %MG_HWND%
  If ((0x00000008 & state) != 0)
    Menu, WH0, Check, 最前面
  else
    Menu, WH0, UnCheck, 最前面
  Menu, WH0, Show
return

WH_Topmost:
  WinSet, Topmost, TOGGLE, ahk_id %MG_HWND%
return

WH_WM:
  WM_X := WM_X%A_ThisMenu%_%A_ThisMenuItemPos%
  WM_Y := WM_Y%A_ThisMenu%_%A_ThisMenuItemPos%
  WM_W := WM_W%A_ThisMenu%_%A_ThisMenuItemPos%
  WM_H := WM_H%A_ThisMenu%_%A_ThisMenuItemPos%
  WinMove, ahk_id %MG_HWND%, , %WM_X%, %WM_Y%, %WM_W%, %WM_H%
return

WH_WK:
  WinKill, ahk_id %MG_HWND%
return

WH_AppDirOpen:
  wmi := ComObjGet("winmgmts:")
  queryEnum := wmi.ExecQuery(""
    . "Select * from Win32_Process where ProcessId=" . MG_PID)
    ._NewEnum()
  if queryEnum[process] {
    RegExMatch(process.CommandLine, """?([^""]+|[^\s]+)""?", $)
    SplitPath, $1, , AppDir
    Run, explore %AppDir%
  }
  wmi := queryEnum := process := ""
return

WH_SettingOpen:
  Run, WinHack.txt
return


; -------- --------- --------- --------- ---------
; 以下をMouseGesture2にインポート
; -------- --------- --------- --------- ---------

[TitleBarButton]
Custom=MG_HitTest()="MinButton"
Custom=MG_HitTest()="MaxButton"
Custom=MG_HitTest()="CloseButton"

[RB__]
G=RB__
TitleBarButton=GoSub,WH_Show

 [TitleBarButton]、右側ボタンだけだと右側見えてない時に無力なので、「タイトルバーのアイコン」とか「枠」「リサイズ可能な枠」あたりも追加した方がよさげ。ただし「ヘルプボタン」はOperaで誤爆するのでお勧めできない

 次に、"MouseGesture.ahk"と同じ位置に"WinHack.txt"を作成し、ウィンドウ移動・サイズ変更設定を書き込む。書式は以下を参考に。

; -------- --------- --------- --------- ---------
; 書式は以下の通り。
;
; ・"["と"]"でサブメニュー化。ネストも可。
; ・"メニュー項目名, X, Y, Width, Height"でウィンドウ移動・サイズ変更項目を作成可能。
; ・";"で始まる行はコメント行。
; ・上の書式に沿わない行(空改行も含む)はセパレータになる。
; -------- --------- --------- --------- ---------

[移動 (&I)
  基準座標に戻す (&W), 0, 0
  タスクバーを避ける, 165, , ,
  ----
  左656, 0, 0, 656 ,1050
  右1024, 656, 0, 1024 ,1050
  右1024, 656, 0, 1024 ,1050
  ----
  左1024, 0, 0, 1024 ,1050
  右656, 1024, 0, 656 ,1050
]
[リサイズ (&R)
  850*635, , ,850 ,635
  1130*850, , ,1130 ,850
  ----
;  800*600, , ,800 ,600
  1024*768, , ,1024 ,768
  1280*1024, , ,1280 ,1024
]


[PR]
by lordnoesis | 2012-01-10 18:03 | テクノロジ | Trackback | Comments(0)

MouseGesture.ahkでウィンドウ操作メニュー表示してみた。

 Windows7環境で古いmenuHackerがソフトを巻き込んで落ちるので困っていたのだが、よく考えたら独自コマンドの表示さえできればいいのだと気づき、MouseGesture.ahkでそれっぽいものを作ってみた。

 mHの設定ファイルっぽいなにかを読み込むようにしたら、ちょっとばかり複雑化。詳しいことはスクリプト読んでもらうとして、簡単に説明すると「タイトルバーで右クリックすると、本物とは別に独自メニューも隅っこに表示される」というシロモノ。



More
[PR]
by lordnoesis | 2012-01-09 19:00 | テクノロジ | Trackback(1) | Comments(0)
ブログトップ | ファンになる