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