﻿;-- TIME_STAMP   2018-07-21 17:59:54   v 0.1

#Region    ;************ Includes ************
#include-once
#include <Array.au3>
#include <WinAPILocale.au3>
#include <WinAPIRes.au3>
#include <WinAPISys.au3>
#include <WinAPIProc.au3>
#EndRegion ;************ Includes ************

; #FUNCTION# ====================================================================================================================
; Name ..........: _MuteWindow
; Description ...: Toggles the sound of an application.
; Syntax ........: _MuteWindow([$vTitle = ''])
; Parameters ....: $vTitle              - [optional] a variant value. Default is '' - the active window.
;                                         the title/hWnd/class of the window.
;                                         the PID or ProcessName of the application.
;                                         the special strings: Systemsounds or Lautsprecher (loudspeaker)
; Return values .: Success: True and set @extended to 1 when the volume mixer has been closed.
;                  Failure: False and sets the @error flag to non-zero
; Author(s) .....: Bitnugger, xTcisloVe
; Modified ......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func _MuteWindow($vTitle = '')
	Local $hWnd, $sTitle, $iWait, $aProcessWindows
	If Not IsHWnd($vTitle) Then $hWnd = WinGetHandle($vTitle)
	Switch True
		Case $vTitle = '' ; Active window
			$sTitle = WinGetTitle('[ACTIVE]')
		Case IsHWnd(HWnd($vTitle)) ; hWnd
			$sTitle = WinGetTitle(HWnd($vTitle))
		Case ProcessExists($vTitle) ; PID or ProcessName
			$aProcessWindows = _WinAPI_EnumProcessWindows(ProcessExists($vTitle))
			If Not @error Then $sTitle =  WinGetTitle($aProcessWindows[1][0])
		Case Else ; ClassName
			Local $aWinList = WinList()
			For $i = 1 To $aWinList[0][0] Step 1
				If _WinAPI_GetClassName($aWinList[$i][1]) = $vTitle Then
					$sTitle &= WinGetTitle($aWinList[$i][1]) & @CRLF
;~ 					ExitLoop
				EndIf
			Next
			If $sTitle = '' And $vTitle <> '' Then $sTitle = $vTitle
	EndSwitch
	If $sTitle = '' Then Return SetError(1, 0, False)
	$sTitle = StringRegExpReplace(StringStripWS($sTitle, 2), '\R{1,}', '|')
	_CW("+ $sTitle      --> " & $sTitle)

	Local $bCloseMixer, $iMixerPID = ProcessExists('sndvol.exe')
	If Not $iMixerPID Then
		$bCloseMixer = True
		$iMixerPID = Run('sndvol.exe')
	EndIf
	If Not $iMixerPID Then Return SetError(2, 0, False)

	Do
		$iWait += Sleep(500)
		$aProcessWindows = _WinAPI_EnumProcessWindows($iMixerPID)
	Until UBound($aProcessWindows) Or $iWait = 10
	If UBound($aProcessWindows) Then
		Local $hMixer = $aProcessWindows[1][0], $aPos = WinGetPos($hMixer), $iClick, $sClassName = 'ToolBarWindow32'
		Local $aSndVolStrings = _GetSndVolString(), $aChildWindows = _WinAPI_EnumChildWindows($hMixer)
		Local $sButtonText, $sPattern = '(' & _ArrayToString($aSndVolStrings, '|') & ')', $sReplace = '(?:' & _ArrayToString($aSndVolStrings, '|') & ').(.+)'

		For $i = 1 To $aChildWindows[0][0] Step 1
			If $aChildWindows[$i][1] = $sClassName Then
				$sButtonText = ControlGetText($aChildWindows[$i][0], '', '')
				If $sButtonText = '' Then ContinueLoop
				$sButtonText = '(' & _ArrayToString(StringRegExp(StringRegExpReplace($sButtonText, $sReplace, '\1'), '([[:alpha:]]{4,})', 3), '|') & ')'
				_CW("> $sButtonText --> " & $sButtonText)
				If StringRegExp($sTitle, $sButtonText) Then
					If $aPos[2] < 699 Then WinMove($hMixer, '', $aPos[0], $aPos[1], 700, $aPos[3], 1)

					Sleep(750) ; Leave the volume mixer window open for a moment to see that it has worked.

					$iClick = ControlClick($hMixer, '', $aChildWindows[$i][0])
					_CW("! $iClick      --> " & $iClick & ' --> ' & $sButtonText)

					ExitLoop
				EndIf
			EndIf
		Next
	EndIf

	Return SetError($iClick ? 0 : 3, $bCloseMixer ? ProcessClose($iMixerPID) : 0, $iClick ? True : False)
EndFunc   ;==>_MuteWindow

; #FUNCTION# ====================================================================================================================
; Name ..........: _GetSndVolString
; Description ...: Determines the text preset in the sndvol.exe for the mute buttons in the currently set language.
; Syntax ........: _GetSndVolString()
; Parameters ....:
; Return values .: Success: A 1-dimensional array that contains the pre-assigned texts of the buttons in the current language.
;                  Failure: False and sets the @error flag to non-zero
; Author(s) .....: Bitnugger
; Modified ......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func _GetSndVolString()
	Local $hInstance = _WinAPI_LoadLibraryEx('C:\Windows\System32\SndVol.exe')
	If Not $hInstance Then Exit MsgBox(BitOR($MB_ICONERROR, $MB_SYSTEMMODAL), @ScriptName, '_GetSndVolString: "C:\Windows\System32\SndVol.exe" not found.')

	; Get the language (locale) identifier for the current process
	Local $iLocale = Number(_WinAPI_GetVersion()) >= 6.0 ? _WinAPI_GetThreadUILanguage() : _WinAPI_GetThreadLocale()

	; Get Resource Languages
	Local $aIDs = [501, 503], $vName = Int($aIDs[0] / 16 + 1), $iIndex, $sRetString, $vRes, $aRes[UBound($aIDs)], $aData = _WinAPI_EnumResourceLanguages($hInstance, $RT_STRING, $vName)
	If Not @error Then
		$iIndex = _ArraySearch($aData, $iLocale, 1)
		If $iIndex = -1 Then $iIndex = 1
		$vRes = _WinAPI_GetVersion() >= 6.0 ? _WinAPI_SetThreadUILanguage($aData[$iIndex]) : _WinAPI_SetThreadLocale($aData[$iIndex])
	EndIf

	; Get the localized string. DE: Stumm für %1 --> "Stumm für ", EN: Mute for %1 --> "Mute for ", ...
	For $i = 0 To UBound($aIDs) -1 Step 1
		$sRetString = StringRegExpReplace(_WinAPI_LoadString($hInstance, $aIDs[$i]), '(.+) %1', '\1')
		If $sRetString Then $aRes[$i] = $sRetString ; _WinAPI_WideCharToMultiByte($sRetString, 65001, True)
	Next

	; Restore the previous language for the current process and free library
	$vRes = _WinAPI_GetVersion() >= 6.0 ? _WinAPI_SetThreadUILanguage($iLocale) : _WinAPI_SetThreadLocale($iLocale)
	_WinAPI_FreeLibrary($hInstance)

	Return $aRes
EndFunc   ;==>_GetSndVolString

Func _CW($sText, $iS = 65001, $iC = 65001)
	ConsoleWrite(StringFormat(_WideCharToMultiByte($sText, $iS, $iC)) & @CRLF)
EndFunc   ;==>_CW

; Konvertiert den Text, damit Umlaute und Sonderzeichen in SciTE und in der Eingabeaufforderung korrekt dargestellt werden!
Func _WideCharToMultiByte($vText, $iSciTE_CodePage = 65001, $iCMD_CodePage = 65001, $bRetString = True)
	$vText = String($vText) ; Damit _WinAPI_WideCharToMultiByte nicht abstürzt, wenn kein String übergeben wurde!

	; SciTE output.code.page = 65001 (UTF-8), Eingabeaufforderung = 1 (OEM 850) + Schriftart, die UTF-8-Zeichen enthält!
;~ 	Return _WinAPI_WideCharToMultiByte($vText, @Compiled ? $iCodePageCompiled : $iSciTE_CodePage, $bRetString)

	; SciTE output.code.page = 0 oder 1252 (ANSI), Eingabeaufforderung = 1 (OEM 850) + Schriftart, die keine UTF-8-Zeichen enthält!
;~ 	Return _WinAPI_WideCharToMultiByte($vText, 0, $bRetString)

	; Ansonsten...
	Return _WinAPI_WideCharToMultiByte($vText, @Compiled ? $iCMD_CodePage : $iSciTE_CodePage, $bRetString)
EndFunc   ;==>_WideCharToMultiByte

;~ Func _MultiByteToWideChar($vText, $iCodePage = 65001, $iFlags = $MB_COMPOSITE, $bRetString = True)
;~ 	Return _WinAPI_MultiByteToWideChar($vText, @Compiled ? 1 : $iCodePage, $iFlags, $bRetString)
;~ EndFunc  ;==>_MultiByteToWideChar
