タグ:AutoHotKey ( 73 ) タグの人気記事

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)

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)

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)
ブログトップ | ファンになる