Jump to content

Automating SoundWire Server's Master Volume slider


Recommended Posts

Hi, I am stuck on a GUI problem and would like your help to solve it.

I am trying to automate the SoundWire Server app to match my current system volume level while it is minimized to the notification area (so no clicking or stealing focus),

I can already get the handle and alter the tracker position by sending a WM_SETPOS message, but somehow the actual volume is not changed: I think I need to do something else to trigger the event handler for the value change and propagate it correctly.

This is the control summary from Au3 info:

>>>> Window <<<<
Title:  SoundWire Server
Class:  #32770
Position:   441, 218
Size:   566, 429
Style:  0x94CA00C4
ExStyle:    0x00050101
Handle: 0x0000000000510E12

>>>> Control <<<<
Class:  msctls_trackbar32
Instance:   4
ClassnameNN:    msctls_trackbar324
Name:   
Advanced (Class):   [CLASS:msctls_trackbar32; INSTANCE:4]
ID: 6002
Text:   
Position:   51, 222
Size:   47, 126
ControlClick Coords:    1, 101
Style:  0x5001000A
ExStyle:    0x00000000
Handle: 0x00000000001234C8

>>>> Mouse <<<<
Position:   496, 567
Cursor ID:  2
Color:  0xF0F0F0

>>>> StatusBar <<<<

>>>> ToolsBar <<<<

>>>> Visible Text <<<<
Default multimedia device
Tray on Start
Static
Server Address:
 192.168.1.8
Status:
 Connected to B9K~OP3
Audio Output          Audio Input                  Level                   Record to File
Input Select:
 44.1 kHz
Minimize to
Master Volume
Mute


>>>> Hidden Text <<<<
Slider2
Mute
OK
Cancel
Label
Balance
Slider1
Volume
Front L/R
Fr C/LFE
Side L/R
Back L/R


I am attaching the program in question so you don't have to install it (i don't know if it is portable enough, tough): 

SoundWire Server_files.zip

Thanks in advance and I hope I didn't post in the wrong section :D

Edited by b9k
more info
Link to post
Share on other sites

On Windows7 I use a DLL to get and put the system volume.  I have done it other ways on XP but I forget atm and I'm at work.

Author: JohnOne

 

Func _SetMasterVolume($vol) ; 0 - 100
    Local $V7Voldll = "W7VVol.dll"
    DllCall($V7Voldll, 'long', 'setvol', 'float', $vol / 100)
    If @error Then
        MsgBox(0, $gScript_name, "_SetMasterVolume(): Error", @error)
        ;Exit MsgBox($gScript_name, "Error", @error)
    EndIf
EndFunc   ;==>_SetMasterVolume

Func _GetMasterVolume()
    Local $V7Voldll = "W7VVol.dll"
    $aDllCall = DllCall($V7Voldll, 'float', 'getvol')
    If @error Then
        MsgBox(0, $gScript_name, "_GetMasterVolume(): Error", @error)
        ;Exit MsgBox(0, "Error", @error)
    EndIf
    Return Round($aDllCall[0], 2) * 100
EndFunc   ;==>_GetMasterVolume

 

W7VVol.dll

Edited by Xandy
Link to post
Share on other sites

Getting the system volume is working, so now the real problem is how to change the "Master Volume" slider in Sound Wire Server. 

I tried to send a TBS_SETPOS window message to the slider control, but while the head is moved no event handler is invoked because the volume does not change.
I believe this may be due to some other window message i need to send or because that GUI seems to be made with qt.

 

image.png

Edited by b9k
Link to post
Share on other sites

Update: I also tried sending TBM_SETPOSNOTIFY but it does not seem to move.

I believe it may be due to the fact that the slider does not normally react to the scrolling wheel and that message's documentation said it uses a scroll message to alert the parent window of the change.

Edited by b9k
more info
Link to post
Share on other sites

@EarthshineHere is the failing code:

#include <SendMessage.au3> ; 1029 is TBM_SETPOS, 1 is to redraw the control, 65535 is the slider position (65535 = 0%, 0 = 100%)
_SendMessage(ControlGetHandle(WinGetHandle("SoundWire Server"), "", "[CLASS:msctls_trackbar32; INSTANCE:4]"), 1029, 1, 65535)

Which actually is the same as using _GUICtrlSlider_SetPos on that control, and it does nothing.


This is the program window before running the code, with volume set to maximum (look at the Level indicator):

image.png.3384b9826351e0dad4251c2a7f05badd.png

 

This is the window after I run the above code (look at the Level indicator, it's still there even if the displayed volume is zero):
image.png.a6ef165a1be6a19e11cb4f366e93446c.png

 

And finally this is the expected result (now the Level indicator is right and the volume is zero for real):


image.png.6463f4f3cc0811ceeaaa9b83263c3532.png

I hope this helps you guys understand my problem :)

Edited by b9k
Link to post
Share on other sites

Figure out the value when the slider is maxed.

I think you can GetPos.  You're still going to need to somehow figure out the Max.  1, 100, 128, 255 are guesses.

Is the max 1?

Max / GetPos = Val?

Something like that, I hate math.

Edit this is where I came up with that idea.

 

Edited by Xandy
Link to post
Share on other sites

Yeah I visited that thread: it was very useful since it gave me the idea to use the TBM_SETPOS message.

In this particular case I don't need to use TBM_GETPOS because the position I am trying to set is a known value: the 65535 in my code.
It will be eventually replaced by a variable holding the correct position based on the volume (the volume value too is in the 0-65535 range so no math needed). 


Now, I only need to be able to set that slider position correctly.

Edited by b9k
Link to post
Share on other sites

I understand now my solution wasn't valid.

I'm not sure how to handle this.  I'll keep thinking about it.

Need to set value of the slider as well as the position.  I'll look for a command and give it a go later if I have time.  You've looked for a GetVal I imagine. :)

Edited by Xandy
Link to post
Share on other sites

@b9k

#include <GuiSlider.au3>

$hCtrl = ControlGetHandle("SoundWire Server", "", "msctls_trackbar324")
$aRange = _GUICtrlSlider_GetRange($hCtrl)
ConsoleWrite($aRange[0] & ":" & $aRange[1] & @CRLF)

_GUICtrlSlider_SetPos($hCtrl, $aRange[1] * 0.5) ; 50%
ControlSend("SoundWire Server", "", $hCtrl, "{up}")
MsgBox(0, "", "50%")

_GUICtrlSlider_SetPos($hCtrl, $aRange[1]) ; min
ControlSend("SoundWire Server", "", $hCtrl, "{up}")
MsgBox(0, "", "min")

_GUICtrlSlider_SetPos($hCtrl, $aRange[1] * 0.3) ; 70%
ControlSend("SoundWire Server", "", $hCtrl, "{up}")
MsgBox(0, "", "70%")

_GUICtrlSlider_SetPos($hCtrl, $aRange[0]) ; max
ControlSend("SoundWire Server", "", $hCtrl, "{up}")
MsgBox(0, "", "max")

 

Link to post
Share on other sites
2 hours ago, InnI said:

@b9k

#include <GuiSlider.au3>

$hCtrl = ControlGetHandle("SoundWire Server", "", "msctls_trackbar324")
$aRange = _GUICtrlSlider_GetRange($hCtrl)
ConsoleWrite($aRange[0] & ":" & $aRange[1] & @CRLF)

_GUICtrlSlider_SetPos($hCtrl, $aRange[1] * 0.5) ; 50%
ControlSend("SoundWire Server", "", $hCtrl, "{up}")
MsgBox(0, "", "50%")

_GUICtrlSlider_SetPos($hCtrl, $aRange[1]) ; min
ControlSend("SoundWire Server", "", $hCtrl, "{up}")
MsgBox(0, "", "min")

_GUICtrlSlider_SetPos($hCtrl, $aRange[1] * 0.3) ; 70%
ControlSend("SoundWire Server", "", $hCtrl, "{up}")
MsgBox(0, "", "70%")

_GUICtrlSlider_SetPos($hCtrl, $aRange[0]) ; max
ControlSend("SoundWire Server", "", $hCtrl, "{up}")
MsgBox(0, "", "max")

 

Thanks, this is very clever indeed! So I needed to "stimulate" a refresh on the app side by sending bogus input: it works flawlessly because in this particular app the {up} and {down} keys do not change the value. But as a thought exercise, what could I have done if they did? I'm wondering... basically I got lucky this time.

I will use this trick in my code, since it works, but I'm still open to other solutions.

Link to post
Share on other sites
4 hours ago, b9k said:

other solution

#include <GuiSlider.au3>
#include <SendMessage.au3>
#include <WindowsConstants.au3>

$iPercent = 30 ; volume % (0-100)

$hWnd = WinGetHandle("SoundWire Server")
$hCtrl = ControlGetHandle($hWnd, "", "msctls_trackbar324")
_GUICtrlSlider_SetPos($hCtrl, (100 - $iPercent) * 655.35)
_SendMessage($hWnd, $WM_VSCROLL, 0, $hCtrl)

 

Link to post
Share on other sites
19 hours ago, InnI said:
#include <GuiSlider.au3>
#include <SendMessage.au3>
#include <WindowsConstants.au3>

$iPercent = 30 ; volume % (0-100)

$hWnd = WinGetHandle("SoundWire Server")
$hCtrl = ControlGetHandle($hWnd, "", "msctls_trackbar324")
_GUICtrlSlider_SetPos($hCtrl, (100 - $iPercent) * 655.35)
_SendMessage($hWnd, $WM_VSCROLL, 0, $hCtrl)

 

Yo, that was what I was thinking when I posted here: a more general approach! Thank you all for your help!

Edited by b9k
Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By XGamerGuide
      I'm trying to assign a faint text in the background to an input field that disappears after the input has started. This should have a certain color such as gray.
    • By kovlad
      My solution is to write nested arrays without copying.
      The problem was described hier.
       
      Function:
      #include <Array.au3> ; #FUNCTION# ==================================================================================================================== ; Name ..........: _ArrayNestedSet ; Description ...: Assigns a value to an element of a nested 1D array. ; Syntax ........: _ArrayNestedSet(ByRef $aArray, $vIndex, $vValue) ; Parameters ....: $aArray - an array of arrays. ; $vIndex - an index or 1d-array of indexes; ; a size if $vValue not defined (zero to delete). ; $vValue - a value (create, resize or delete if not defined). ; ; Return values .: on success - 1 ; @extended - nesting level of operation ; on failure - 0 ; @extended - nesting level of error ; @error = 1 - invalid array ; @error = 2 - invalid index ; Author ........: ; Modified ......: kovlad ; Remarks .......: ; Related .......: ; Link ..........: https://www.autoitscript.com/forum/topic/185638-assign-a-value-to-an-array-in-array-element/ ; https://www.autoitscript.com/trac/autoit/ticket/3515?replyto=description ; Example .......: Yes ; =============================================================================================================================== Func _ArrayNestedSet(ByRef $aArray, $vIndex, $vValue = Default) Local $extended = @extended + 1 If IsArray($vIndex) Then If UBound($vIndex, 0) <> 1 Then _ Return SetError(2, $extended) If UBound($vIndex) > 1 Then If UBound($aArray, 0) <> 1 Then _ Return SetError(1, $extended) ; keep index for this array Local $i = $vIndex[0] If $i < 0 Or UBound($aArray) <= $i Then _ Return SetError(2, $extended) ; delete index of this array _ArrayDelete($vIndex, 0) ; recursive function call Local $return = _ArrayNestedSet($aArray[$i], $vIndex, $vValue) If @error Then Return SetError(@error, @extended + 1, 0) Else Return SetExtended(@extended + 1, 1) EndIf Else $vIndex = $vIndex[0] EndIf EndIf If $vValue = Default Then If $vIndex < 0 Then _ Return SetError(2, $extended) If $vIndex = 0 Then ; delete array and free memory $aArray = 0 Return SetExtended($extended, 1) EndIf If UBound($aArray, 0) = 1 Then ; resize array keeping data ReDim $aArray[$vIndex] Return SetExtended($extended, 1) Else ; create new nested array Local $aTmp[$vIndex] $aArray = $aTmp Return SetExtended($extended, 1) EndIf Else If UBound($aArray) <= $vIndex Then _ Return SetError(2, $extended + 1) ; set value of array entry $aArray[$vIndex] = $vValue Return SetExtended($extended, 1) EndIf EndFunc  
      Examples:
      ; write value to 1st nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : write value to 1st nested array" & @CRLF) Local $aTmp1[4] = [1,2,3,4] _ArrayDisplay($aTmp1, "$aTmp1") Local $aArray[2] = [$aTmp1] ConsoleWrite( _ "_ArrayNestedSet($aArray[0], 3, 14) = " & _ArrayNestedSet($aArray[0], 3, 14) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay($aArray[0], "$aArray[0]") ; resize 1st nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : resize 1st nested array" & @CRLF) ConsoleWrite( _ "_ArrayNestedSet($aArray[0], 8) = " & _ArrayNestedSet($aArray[0], 8) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay($aArray[0], "$aArray[0]") ; write array to 1st nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : write array to 1st nested array" & @CRLF) Local $aTmp11[4] = [11,12,13,14] _ArrayDisplay($aTmp11, "$aTmp11") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], 2, $aTmp11) = " & _ArrayNestedSet($aArray[0], 2, $aTmp11) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay(($aArray[0])[2], "($aArray[0])[2]") ; write value to 2nd nested array using index array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : write value to 2nd nested array using index array" & @CRLF) Local $aIndex1[2] = [2,3] _ArrayDisplay($aIndex1, "$aIndex1") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex1, 140) = " & _ArrayNestedSet($aArray[0], $aIndex1, 140) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay(($aArray[0])[2], "($aArray[0])[2]") ; resize 2nd nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : resize 2nd nested array" & @CRLF) Local $aIndex1[2] = [2,8] _ArrayDisplay($aIndex1, "$aIndex1") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex1) = " & _ArrayNestedSet($aArray[0], $aIndex1) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay(($aArray[0])[2], "($aArray[0])[2]") ; create new 3rd nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : create new 3rd nested array" & @CRLF) Local $aIndex2[3] = [2,7,6] _ArrayDisplay($aIndex2, "$aIndex2") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex2) = " & _ArrayNestedSet($aArray[0], $aIndex2) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay((($aArray[0])[2])[7], ")($aArray[0])[2])[7]") ; delete 3rd nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : delete 3rd nested array" & @CRLF) Local $aIndex3[3] = [2,7,0] _ArrayDisplay($aIndex3, "$aIndex2") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex3) = " & _ArrayNestedSet($aArray[0], $aIndex3) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF) ConsoleWrite("IsArray((($aArray[0])[2])[7]) = " & IsArray((($aArray[0])[2])[7]) & @CRLF & @CRLF) ; write 0 in 1st nested array to delete the 2nd nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : write 0 in 1st nested array to delete the 2nd nested array" & @CRLF) Local $aIndex4[1] = [2] _ArrayDisplay($aIndex4, "$aIndex4") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex4, 0) = " & _ArrayNestedSet($aArray[0], $aIndex4, 0) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF) ConsoleWrite("IsArray(($aArray[0])[2]) = " & IsArray(($aArray[0])[2]) & @CRLF & @CRLF) ; delete 1st nested array (same as '$aArray[0] = 0') ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : delete 1st nested array (same as '$aArray[0] = 0')" & @CRLF) Local $aIndex5[1] = [0] _ArrayDisplay($aIndex5, "$aIndex5") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex5) = " & _ArrayNestedSet($aArray[0], $aIndex5) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF) ConsoleWrite("IsArray($aArray[0]) = " & IsArray($aArray[0]) & @CRLF & @CRLF)  
    • By kcvinu
      Hi all,
      I am creating a GUI library in Nim with win32 API functions. Even though the syntax is similar to Python, coding is almost similar to C in Nim. 
      I can change the back color of the button in NM_CUSTOMDRAW. But I can't change the button text color. here is my pseudo code.  
      proc setBtnBackColor*(me : Button, lp: LPNMCUSTOMDRAW ) = if lp.uItemState and CDIS_SELECTED : #------------------ btn clicked # Here i am changing the button color with SelectObject & FillRect. elif lp.uItemState and CDIS_HOT : # ----------------Mouse over # Here i am changing the button's mouse hover color with SelectObject & FillRect. else: # -------------------------Default color set # Here i am changing the button's default color with SelectObject & FillRect. # Here i tried---> SetTextColor(lp.hdc, RGB(102, 255, 51) ) #------- But no luck. #------------------------------------------------------------------------- Please guide me. What i am doing wrong here ?  I am returning "CDRF_SKIPDEFAULT" after calling this function.
      Note : I am using subclassed button. So when the parent window receives WM_NOTIFY message, it sends that to my button's WndProc. There i am handling the message.
    • By Luigi
      Greetings,
       
      Someone can help-me to translate this Python's code to AutoIt?
       
      Python (source: https://repl.it/repls/InstructiveDarkslategreyJackrabbit)
      str = 'age=12,name=bob,hobbies="games,reading",phrase="I\'m cool!"' key = "" val = "" dict = {} parse_string = False parse_key = True # parse_val = False for c in str: print(c) if c == '"' and not parse_string: parse_string = True continue elif c == '"' and parse_string: parse_string = False continue if parse_string: val += c continue if c == ',': # terminate entry dict[key] = val #add to dict key = "" val = "" parse_key = True continue elif c == '=' and parse_key: parse_key = False elif parse_key: key += c else: val+=c dict[key] = val print(dict.items()) Python's output:
      [('phrase', "I'm cool!"), ('age', '12'), ('name', 'bob'), ('hobbies', 'games,reading')] AutoIt
      #include-once #include <Array.au3> #include <StringConstants.au3> Global $opt $opt = "estado = """" , cep = """", idade=32, nome = ""Luismar"", campo=""campo = campo""" $opt = "age=12,name=bob,hobbies=""games,reading"",phrase=""I\'m cool!""" ConsoleWrite($opt & @LF) Local $arr = StringSplit($opt, "", $STR_CHRSPLIT) Local $key = "" Local $val = "" Local $dict = ObjCreate("Scripting.Dictionary") Local $parse_string = False Local $parse_key = True Local $c For $ii = 1 To $arr[0] $c = $arr[$ii] If $c == '"' And Not $parse_string Then $parse_string = True ContinueLoop ElseIf $c == """" And $parse_string Then $parse_string = False ContinueLoop EndIf If $parse_string Then $val &= $c ContinueLoop EndIf If $c = "," Then $dict.Add($key, $val) $key = "" $val = "" $parse_key = True ContinueLoop ElseIf $c == "=" And $parse_key Then $parse_key = False ElseIf $parse_key Then $key &= $c Else $val &= $c EndIf Next $dict.Add($key, $val) ; missing this line... For $each In $dict ConsoleWrite($each & " = " & $dict.Item($each) & @LF) Next AutoIt's output
      age=12,name=bob,hobbies="games,reading",phrase="I\'m cool!" age = 12 name = bob hobbies = games,reading  
      Best regards.
       
    • By Schuster
      Hey there,
      i need your help guys. I am working in the QA department of my company. A little part of or software produces hints (like little popups) which needs to be tested every release. I wrote scripts to trigger those hints and i also implemented the imagesearch.dll to find those hints on the screen. My goal now is it to let the machine work over night, so when i come back to work i only get a report which says 130/140 hints were found successfully. This already works, aslong as my pc is not locked, but i want/need to lock my pc because of security concerns.
      My general question. Is it possible to run my scripts on my locked PC and still find an image that i provide which will open sooner or later in the background?
       
      Thanks in advance
×
×
  • Create New...