Disable, then re enable a microphone after coming out of sleep Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
monorchid

Disable, then re enable a microphone after coming out of sleep

09 Mar 2016, 19:55

I have no idea how to do it D:.

Whenever I come out of sleep, my microphone does not work until I reinitialize it, and its killing me inside from doing it for over a year. Any suggestions on a script to automate this process for me?

Thank you!
wizardzedd
Posts: 319
Joined: 23 Jan 2016, 23:03

Re: Disable, then re enable a microphone after coming out of sleep

09 Mar 2016, 21:14

For starters:

Code: Select all

SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
SetTitleMatchMode, 2 ; partial titles
if not A_IsAdmin
{
   Run, *RunAs "%A_ScriptFullPath%"
   ExitApp
}
Run, devmgmt.msc
WinWait, Device Manager
Device=Microphone
ControlSend, SysTreeView321, {tab}Audio{Right}%Device%{Enter}
WinWait, % Device
Control, TabRight,, SysTabControl321
send, !e!o		; Enable ok
WinClose % Device
WinClose, Device Manager

Then you will need to have the script ran when it comes out of sleep, probably with task scheduler.
monorchid

Re: Disable, then re enable a microphone after coming out of sleep

09 Mar 2016, 23:15

Thanks for the reply!

I tried it out, and it did not work at first. I changed microhone in the script to Corsair Vegeance 1500 Headset, which makes the script execute correctly. However, it does not seem to disable my headset whatsoever... For example, the audio stream is not interrupted while watching a youtube video, and my microphone does not seem to work.

The way I disable/enable it is through the windows Sound. The one with Playback/Recording/Sounds/Communication -- Maybe this is the correct avenue of approach? I say this because device manager doesn't list the microphone seperately, just the headset and isn't work as current.

Thanks again for the script and the view Wizardzedd!
wizardzedd
Posts: 319
Joined: 23 Jan 2016, 23:03

Re: Disable, then re enable a microphone after coming out of sleep

10 Mar 2016, 02:14

I went big mode lol, although I was surprised that I didn't find a simpler way to click a listview item. Anyway here you are:

Code: Select all

device:="Microphone" ; change to your device
sounds:=new C_Sounds()	; Sounds window
sounds.activateRecording()	; Activate Recording Tab
properties:=sounds.openProperties(device)	; Open properties of device
currentSetting:=properties.choice			; retrieve current setting
properties.setChoice(instr(currentSetting, "enable") ? "disable" : "enable") ; toggle setting
properties.Close()	; close properties
sounds.Close()		; close sounds
return
esc::ExitApp

class C_Sounds	
{
	static winTitle:="Sound"
	__New() {
		if(!this.hwnd:=WinExist(WinTitle))
			this.hwnd:=this.Open()
		this.hwnd:="ahk_id" this.hwnd
	}
	; Open
	Open() {		
		Run, %ComSpec% /C control mmsys.cpl sounds
		WinWait, % this.winTitle,, 3
		return WinExist(this.WinTitle)
	}
	; Close
	Close() {
		WinClose, % this.hwnd
	}
	
	; =============================== LISTVIEW =============================
	; Open Properties
	openProperties(Name) {
		if(this.selectListItem(Name)) {
			send !p
			return new C_PropertiesWindow()
		}
		return false
	}
	
	; Select ListView Item
	selectListItem(Name) {
		ControlGet, list, list,, SysListView321, % this.hwnd
		Loop, Parse, list, `n
			if(instr(A_LoopField, Name)) {
				LVSel(this.hwnd, A_Index-1)
				return true
			}
		return false
	}
	
	; ============= TABS =================
	activatePlayback() {
		return this.activateTab(1)
	}
	activateRecording() {
		return this.activateTab(2)
	}
	activateSounds() {
		return this.activateTab(3)
	}
	activateCommunications() {
		return this.activateTab(4)
	}
	activateTab(n) {
		if(tab:=n-this.getTab()) {
			if(tab > 0)
				control, TabRight, % tab, SysTabControl321, % this.hwnd
			else
				control, TabLeft, % tab*-1, SysTabControl321, % this.hwnd
		}
		return !ErrorLevel
	}
	getTab() {
		controlget, tab, tab,, SysTabControl321, % this.hwnd
		return tab
	}
}

class C_PropertiesWindow
{
	static WinTitle:="Properties"
	static classNN:="ComboBox1"
	__New() {
		SetTitleMatchMode, 2
		WinWait, % this.WinTitle, , 1
		if(ErrorLevel)
			return false
		this.hwnd:="ahk_id" winExist(this.WinTitle)
		controlget, choice, choice, , % this.classNN, % this.hwnd
		this.choice:=choice
	}
	
	setChoice(choice) {
		if(instr(choice, this.choice))
			return true
		controlget, list, list, , % this.classNN, % this.hwnd
		Loop, Parse, list, `n
			if(instr(A_LoopField, choice))
				i:=A_Index, this.choice:=A_LoopField, break
		control, choose, %i%, % this.classNN, % this.hwnd
		return !ErrorLevel
	}
	Close(save=true) {
		if(save)
			ControlClick, Button6, % this.hwnd,,, 2
		else
			WinClose, % this.hwnd
	}
}

LVSel(WinTitle, r=0)
{
	VarSetCapacity(LVITEM, 20, 0) ;to receive LVITEM
;	LVIS_FOCUSED:=1   LVIS_SELECTED:=2
	NumPut(1 | 2, LVITEM, 12)  ; state
	NumPut(1 | 2, LVITEM, 16)  ; stateMask
	RemoteBuf_Open(hLVITEM, WinExist(WinTitle), 20)  ; MASTER_ID = the ahk_id of the process owning the SysListView32 control
	RemoteBuf_Write(hLVITEM, LVITEM,20)
	SendMessage, 0x102B,r,RemoteBuf_Get(hLVITEM), SysListView321,%WinTitle%   ; LVM_SETITEMSTATE:=0x102B
	RemoteBuf_Close(hLVITEM)
}
;   
;	Title:	Remote Buffer
;			*Read and write process memory*
;
/*-------------------------------------------------------------------------------
	Function: Open
			  Open remote buffer

	Parameters:
			H		- Reference to variable to receive remote buffer handle
			hwnd    - HWND of the window that belongs to the process
			size    - Size of the buffer

	Returns:
			Error message on failure
 */
RemoteBuf_Open(ByRef H, hwnd, size) {
	static MEM_COMMIT=0x1000, PAGE_READWRITE=4

	WinGet, pid, PID, ahk_id %hwnd%
	hProc   := DllCall( "OpenProcess", "uint", 0x38, "int", 0, "uint", pid) ;0x38 = PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE
	IfEqual, hProc,0, return A_ThisFunc ">   Unable to open process (" A_LastError ")"

	bufAdr  := DllCall( "VirtualAllocEx", "uint", hProc, "uint", 0, "uint", size, "uint", MEM_COMMIT, "uint", PAGE_READWRITE)
	IfEqual, bufAdr,0, return A_ThisFunc ">   Unable to allocate memory (" A_LastError ")"

	; Buffer handle structure:
	 ;	@0: hProc
	 ;	@4: size
	 ;	@8: bufAdr
	VarSetCapacity(H, 12, 0 )
	NumPut( hProc,	H, 0)
	NumPut( size,	H, 4)
	NumPut( bufAdr, H, 8)
}

/*----------------------------------------------------
	Function: Close
			  Close the remote buffer

	Parameters:
			  H - Remote buffer handle
 */
RemoteBuf_Close(ByRef H) {
	static MEM_RELEASE = 0x8000

	handle := NumGet(H, 0)
	IfEqual, handle, 0, return A_ThisFunc ">   Invalid remote buffer handle"
	adr    := NumGet(H, 8)

	r := DllCall( "VirtualFreeEx", "uint", handle, "uint", adr, "uint", 0, "uint", MEM_RELEASE)
	ifEqual, r, 0, return A_ThisFunc ">   Unable to free memory (" A_LastError ")"
	DllCall( "CloseHandle", "uint", handle )
	VarSetCapacity(H, 0 )
}

/*----------------------------------------------------
	Function:   Read
				Read from the remote buffer into local buffer

	Parameters:
         H			- Remote buffer handle
         pLocal		- Reference to the local buffer
         pSize		- Size of the local buffer
         pOffset	- Optional reading offset, by default 0

Returns:
         TRUE on success or FALSE on failure. ErrorMessage on bad remote buffer handle
 */
RemoteBuf_Read(ByRef H, ByRef pLocal, pSize, pOffset = 0){
	handle := NumGet( H, 0),   size:= NumGet( H, 4),   adr := NumGet( H, 8)
	IfEqual, handle, 0, return A_ThisFunc ">   Invalid remote buffer handle"
	IfGreaterOrEqual, offset, %size%, return A_ThisFunc ">   Offset is bigger then size"

	VarSetCapacity( pLocal, pSize )
	return DllCall( "ReadProcessMemory", "uint", handle, "uint", adr + pOffset, "uint", &pLocal, "uint", size, "uint", 0 ), VarSetCapacity(pLocal, -1)
}

/*----------------------------------------------------
	Function:   Write
				Write local buffer into remote buffer

	Parameters:
         H			- Remote buffer handle
         pLocal		- Reference to the local buffer
         pSize		- Size of the local buffer
         pOffset	- Optional writting offset, by default 0

	Returns:
         TRUE on success or FALSE on failure. ErrorMessage on bad remote buffer handle
 */

RemoteBuf_Write(Byref H, byref pLocal, pSize, pOffset=0) {
	handle:= NumGet( H, 0),   size := NumGet( H, 4),   adr := NumGet( H, 8)
	IfEqual, handle, 0, return A_ThisFunc ">   Invalid remote buffer handle"
	IfGreaterOrEqual, offset, %size%, return A_ThisFunc ">   Offset is bigger then size"

	return DllCall( "WriteProcessMemory", "uint", handle,"uint", adr + pOffset,"uint", &pLocal,"uint", pSize, "uint", 0 )
}

/*----------------------------------------------------
	Function:   Get
				Get address or size of the remote buffer

	Parameters:
         H		- Remote buffer handle
         pQ     - Query parameter: set to "adr" to get address (default), to "size" to get the size or to "handle" to get Windows API handle of the remote buffer.

	Returns:
         Address or size of the remote buffer
 */
RemoteBuf_Get(ByRef H, pQ="adr") {
	return pQ = "adr" ? NumGet(H, 8) : pQ = "size" ? NumGet(H, 4) : NumGet(H)
}
monorchid

Re: Disable, then re enable a microphone after coming out of sleep

10 Mar 2016, 02:43

Wow! that is ridiculous what you wrote.

I would have been really lost if I tried to make it myself, haha...

However, one issue. Its failing once it opens the microphone tab, even with the correct name(Microphone is correct, double checked.) It doesn't open up the properties of microphone, and just closes after a short delay. It does not reset it either, I double checked just in case it was extremely fast. Sorry to be such a pain!


Again, thanks a bunch!
wizardzedd
Posts: 319
Joined: 23 Jan 2016, 23:03

Re: Disable, then re enable a microphone after coming out of sleep

10 Mar 2016, 11:59

ok I added more code, and changed to listview double click to open the properties window. Try this out (oh and make sure you show disabled devices):

Code: Select all

#SingleInstance, force 
device:="Microphone" ; change to your device
sounds:=new C_Sounds()	; Sounds window
sounds.activateRecording()	; Activate Recording Tab
properties:=sounds.openProperties(device)	; Open properties of device
while(!IsObject(properties) && !Abort) {
	MsgBox, 18, Property Object Error, Failed to open properties window.
	IfMsgBox, Abort
		Abort:=true
}
if(!Abort) {
	currentSetting:=properties.choice			; retrieve current setting
	properties.setChoice(instr(currentSetting, "enable") ? "disable" : "enable") ; toggle setting
	;~ MsgBox, % "current setting is " properties.choice
	properties.Close()	; close properties
}
sounds.Close()		; close sounds
return
esc::ExitApp

class C_Sounds	
{
	static winTitle:="Sound"
	__New() {
		if(!this.hwnd:=WinExist(WinTitle))
			this.hwnd:=this.Open()
		this.hwnd:="ahk_id" this.hwnd
	}
	; Open
	Open() {		
		Run, %ComSpec% /C control mmsys.cpl sounds
		WinWait, % this.winTitle,, 3
		return WinExist(this.WinTitle)
	}
	; Close
	Close() {
		WinClose, % this.hwnd
	}
	
	; =============================== LISTVIEW =============================
	; Open Properties
	openProperties(Name="") {
		if(Name="") {
			ControlClick, Button3, % this.hwnd,, , 1
			return new C_PropertiesWindow()
		} else if(this.doubleClickListItem(Name)) {
			return new C_PropertiesWindow()
		}
		return false
	}
	
	; Select ListView Item
	selectListItem(Name) {
		if(r:=this.getListItemRow(Name)) 
			LVSel(this.hwnd, r)
		return r
	}
	
	doubleClickListItem(Name) {
		if(r:=this.getListItemRow(Name)) {
			controlget, lvHwnd, hwnd,, SysListView321, % this.hwnd
			LV_DoubleClickRow(lvHwnd, r)
		}
		return r		
	}
	
	; Get List item row
	getListItemRow(Name) {
		ControlGet, list, list,, SysListView321, % this.hwnd
		Loop, Parse, list, `n
			if(instr(A_LoopField, Name))
				return A_Index
		return 0
	}
	
	; ============= TABS =================
	activatePlayback() {
		return this.activateTab(1)
	}
	activateRecording() {
		return this.activateTab(2)
	}
	activateSounds() {
		return this.activateTab(3)
	}
	activateCommunications() {
		return this.activateTab(4)
	}
	activateTab(n) {
		if(tab:=n-this.getTab()) {
			if(tab > 0)
				control, TabRight, % tab, SysTabControl321, % this.hwnd
			else
				control, TabLeft, % tab*-1, SysTabControl321, % this.hwnd
		}
		return !ErrorLevel
	}
	getTab() {
		controlget, tab, tab,, SysTabControl321, % this.hwnd
		return tab
	}
}

class C_PropertiesWindow
{
	static WinTitle:="Properties"
	static classNN:="ComboBox1"
	__New() {
		SetTitleMatchMode, 2
		WinWait, % this.WinTitle, , 1
		;~ logM("Found win?" ErrorLevel)
		if(ErrorLevel)
			return false
		this.hwnd:="ahk_id" winExist(this.WinTitle)
		controlget, choice, choice, , % this.classNN, % this.hwnd
		this.choice:=choice
	}
	
	setChoice(choice) {
		if(instr(choice, this.choice))
			return true
		controlget, list, list, , % this.classNN, % this.hwnd
		;~ logM(list)
		Loop, Parse, list, `n
			if(instr(A_LoopField, choice))
				i:=A_Index, this.choice:=A_LoopField, break
		;~ logM("choosing " i)
		control, choose, %i%, % this.classNN, % this.hwnd
		return !ErrorLevel
	}
	Close(save=true) {
		if(save) {
			ControlClick, Button6, % this.hwnd,,, 1
			WinWaitClose, % this.hwnd,, 1
			if(ErrorLevel) {
				ControlClick, Button6, % this.hwnd,,, 1
				WinWaitClose, % this.hwnd,, 1
			}
			return !ErrorLevel
		}
		else
			WinClose, % this.hwnd
		return true
	}
}

; Thanks to just me!
LV_DoubleClickRow(HLV, Row) {
   ; HLV : ListView's HWND, Row : 1-based row number
   HPROC := 0
   MyPID := DllCall("GetCurrentProcessId", "UInt")
   WinGet, LVPID, PID, ahk_id %HLV%
   If !(LVPID)
      Return False
   VarSetCapacity(RECT, 16, 0)
   If (LVPID <> MyPID) {
      If !(HPROC := DllCall("OpenProcess", "UInt", 0x0438, "Int", False, "UInt", LVPID, "Ptr"))
         Return False
      If !(Addr := DllCall("VirtualAllocEx", "Ptr", HPROC, "Ptr", 0, "UPtr", 16, "UInt", 0x1000, "UInt", 4, "UPtr"))
         Return (DllCall("CloseHandle", "Ptr", HPROC) & 0) ; False
   }
   Else
      Addr := &RECT
   SendMessage, 0x1013, % (Row - 1), 1, , ahk_id %HLV% ; LVM_ENSUREVISIBLE
   SendMessage, 0x100E, % (Row - 1), %Addr%, , ahk_id %HLV% ; LVM_GETITEMRECT
   If (HPROC) {
      DllCall("ReadProcessMemory", "Ptr", HPROC, "Ptr", Addr, "Ptr", &RECT, "UPtr", 16, "Ptr", 0)
      DllCall("VirtualFreeEx", "Ptr", HPROC, "Ptr", Addr, "UPtr", 0, "UInt", 0x8000)
      DllCall("CloseHandle", "Ptr", HPROC)
   }
   POINT := NumGet(RECT, 0, "Short") | (NumGet(RECT, 4, "Short") << 16)
   PostMessage, 0x0201, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONDOWN
   PostMessage, 0x0202, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONUP
   PostMessage, 0x0203, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONDBLCLK
   PostMessage, 0x0202, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONUP
   Return True
}

LVSel(WinTitle, r=0)
{
	--r
	VarSetCapacity(LVITEM, 20, 0) ;to receive LVITEM
;	LVIS_FOCUSED:=1   LVIS_SELECTED:=2
	NumPut(1 | 2, LVITEM, 12)  ; state
	NumPut(1 | 2, LVITEM, 16)  ; stateMask
	RemoteBuf_Open(hLVITEM, WinTitle, 20)  ; MASTER_ID = the ahk_id of the process owning the SysListView32 control
	RemoteBuf_Write(hLVITEM, LVITEM,20)
	SendMessage, 0x102B,r,RemoteBuf_Get(hLVITEM), SysListView321,%WinTitle%   ; LVM_SETITEMSTATE:=0x102B
	RemoteBuf_Close(hLVITEM)
}
;   
;	Title:	Remote Buffer
;			*Read and write process memory*
;
/*-------------------------------------------------------------------------------
	Function: Open
			  Open remote buffer

	Parameters:
			H		- Reference to variable to receive remote buffer handle
			hwnd    - HWND of the window that belongs to the process
			size    - Size of the buffer

	Returns:
			Error message on failure
 */
RemoteBuf_Open(ByRef H, WinTitle, size) {
	static MEM_COMMIT=0x1000, PAGE_READWRITE=4
	WinGet, pid, PID, %WinTitle%
	hProc   := DllCall( "OpenProcess", "uint", 0x38, "int", 0, "uint", pid) ;0x38 = PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE
	IfEqual, hProc,0, return A_ThisFunc ">   Unable to open process (" A_LastError ")"
	bufAdr  := DllCall( "VirtualAllocEx", "uint", hProc, "uint", 0, "uint", size, "uint", MEM_COMMIT, "uint", PAGE_READWRITE)
	IfEqual, bufAdr,0, return A_ThisFunc ">   Unable to allocate memory (" A_LastError ")"
	; Buffer handle structure:
	 ;	@0: hProc
	 ;	@4: size
	 ;	@8: bufAdr
	VarSetCapacity(H, 12, 0 )
	NumPut( hProc,	H, 0)
	NumPut( size,	H, 4)
	NumPut( bufAdr, H, 8)
}

/*----------------------------------------------------
	Function: Close
			  Close the remote buffer

	Parameters:
			  H - Remote buffer handle
 */
RemoteBuf_Close(ByRef H) {
	handle := NumGet(H, 0)
	IfEqual, handle, 0, return A_ThisFunc ">   Invalid remote buffer handle"
	adr    := NumGet(H, 8)
	r := DllCall( "VirtualFreeEx", "uint", handle, "uint", adr, "uint", 0, "uint", 0x8000) ; MEM_RELEASE
	ifEqual, r, 0, return A_ThisFunc ">   Unable to free memory (" A_LastError ")"
	DllCall( "CloseHandle", "uint", handle )
	VarSetCapacity(H, 0 )
}

/*----------------------------------------------------
	Function:   Read
				Read from the remote buffer into local buffer

	Parameters:
         H			- Remote buffer handle
         pLocal		- Reference to the local buffer
         pSize		- Size of the local buffer
         pOffset	- Optional reading offset, by default 0

Returns:
         TRUE on success or FALSE on failure. ErrorMessage on bad remote buffer handle
 */
RemoteBuf_Read(ByRef H, ByRef pLocal, pSize, pOffset = 0){
	handle := NumGet( H, 0),   size:= NumGet( H, 4),   adr := NumGet( H, 8)
	IfEqual, handle, 0, return A_ThisFunc ">   Invalid remote buffer handle"
	IfGreaterOrEqual, offset, %size%, return A_ThisFunc ">   Offset is bigger then size"

	VarSetCapacity( pLocal, pSize )
	return DllCall( "ReadProcessMemory", "uint", handle, "uint", adr + pOffset, "uint", &pLocal, "uint", size, "uint", 0 ), VarSetCapacity(pLocal, -1)
}

/*----------------------------------------------------
	Function:   Write
				Write local buffer into remote buffer

	Parameters:
         H			- Remote buffer handle
         pLocal		- Reference to the local buffer
         pSize		- Size of the local buffer
         pOffset	- Optional writting offset, by default 0

	Returns:
         TRUE on success or FALSE on failure. ErrorMessage on bad remote buffer handle
 */
RemoteBuf_Write(Byref H, byref pLocal, pSize, pOffset=0) {
	handle:= NumGet( H, 0),   size := NumGet( H, 4),   adr := NumGet( H, 8)
	IfEqual, handle, 0, return A_ThisFunc ">   Invalid remote buffer handle"
	IfGreaterOrEqual, offset, %size%, return A_ThisFunc ">   Offset is bigger then size"
	return DllCall( "WriteProcessMemory", "uint", handle,"uint", adr + pOffset,"uint", &pLocal,"uint", pSize, "uint", 0 )
}

/*----------------------------------------------------
	Function:   Get
				Get address or size of the remote buffer

	Parameters:
         H		- Remote buffer handle
         pQ     - Query parameter: set to "adr" to get address (default), to "size" to get the size or to "handle" to get Windows API handle of the remote buffer.

	Returns:
         Address or size of the remote buffer
 */
RemoteBuf_Get(ByRef H, pQ="adr") {
	return pQ = "adr" ? NumGet(H, 8) : pQ = "size" ? NumGet(H, 4) : NumGet(H)
}
monorchid

Re: Disable, then re enable a microphone after coming out of sleep

10 Mar 2016, 18:20

This is almost there! IT does indeed disable my microphone(most of the time), but does not re enable it afterwards. I tried to modify it like so:

Code: Select all

#SingleInstance, force 
device:="Microphone" ; change to your device
sounds:=new C_Sounds()	; Sounds window
sounds.activateRecording()	; Activate Recording Tab
properties:=sounds.openProperties(device)	; Open properties of device
while(!IsObject(properties) && !Abort) {
	MsgBox, 18, Property Object Error, Failed to open properties window.
	IfMsgBox, Abort
		Abort:=true
}
if(!Abort) {
	currentSetting:=properties.choice			; retrieve current setting
	properties.setChoice(instr(currentSetting, "enable") ? "disable" : "enable") ; toggle setting
	sleep, 500
	properties.setChoice(instr(currentSetting, "disable") ? "disable" : "enable") ; toggle setting
	;~ MsgBox, % "current setting is " properties.choice
	properties.Close()	; close properties
	sleep, 200
}
sounds.Close()		; close sounds
return
ExitApp
1. Make it disable, then re enable after. However I think its missing a click apply button in between those two events, and I couldn't figure out how yours does it :/. Also, half the time it did not actually finish, it would open the properties of the microphone but then do nothing, aka not switch the source on or off or close the window. I added some sleeps to hopefuly fix that problem, but my fix does not work that well. I'm not sure if the sleeps need to be longer or if something else is wrong. Lastly, I made autohotkey exit unconditionally, I assume you had it end on esc for debugging purposes?

Thanks for all the help Zedd!
wizardzedd
Posts: 319
Joined: 23 Jan 2016, 23:03

Re: Disable, then re enable a microphone after coming out of sleep

10 Mar 2016, 19:33

In your code the currentSetting has not changed. What has changed is the properties.choice. Currently it works perfectly (for me, I could probably remove the abort code as well).
Also, half the time it did not actually finish, it would open the properties of the microphone but then do nothing
It shouldn't. I can't imagine why since the only winwaits I have also time out fairly quickly. It should set the choice and hit "Ok" (which both applies the setting and closes the window.) Now there could exist a problem if there is another window with "properties" in the title open... I updated so it should no longer be a problem.
I assume you had it end on esc for debugging purposes?
Indeed I did.

I'm assuming you were attempting enabling and disabling for testing purposes only? If you want to simply enable the setting you could just do:
properties.setChoice("enable")

Code: Select all

;
; AutoHotkey Version: 1.1.23.01
; Language:       English
; Platform:       Windows 10
; Author:         WizardZedd
;
; Script Function:
;	Enable Sound device Microphone.
;
#SingleInstance, force 
device:="Microphone" ; change to your device
sounds:=new C_Sounds()	; Sounds window
sounds.activateRecording()	; Activate Recording Tab
properties:=sounds.openProperties(device)	; Open properties of device
while(!IsObject(properties:=sounds.openProperties(device)) && !Abort) {
	MsgBox, 18, Property Object Error, Failed to open properties window.
	IfMsgBox, Abort
		Abort:=true
}
if(!Abort) {
	properties.setChoice("enable") ; enable
	properties.Close()	; close properties
}
sounds.Close()
return

class C_Sounds	
{
	static winTitle:="Sound"
	__New() {
		if(!this.hwnd:=WinExist(WinTitle))
			this.hwnd:=this.Open()
		this.hwnd:="ahk_id" this.hwnd
	}
	; Open
	Open() {		
		Run, %ComSpec% /C control mmsys.cpl sounds
		WinWait, % this.winTitle,, 3
		return WinExist(this.WinTitle)
	}
	; Close
	Close() {
		WinClose, % this.hwnd
	}
	
	; =============================== LISTVIEW =============================
	; Open Properties
	openProperties(Name="") {
		if(Name="") {
			ControlClick, Button3, % this.hwnd,, , 1
			return new C_PropertiesWindow()
		} else if(this.doubleClickListItem(Name)) {
			return new C_PropertiesWindow(Name)
		}
		return false
	}
	
	; Select ListView Item
	selectListItem(ByRef Name) {
		if(r:=this.getListItemRow(Name)) 
			LVSel(this.hwnd, r)
		return r
	}
	
	doubleClickListItem(ByRef Name) {
		if(r:=this.getListItemRow(Name)) {
			controlget, lvHwnd, hwnd,, SysListView321, % this.hwnd
			LV_DoubleClickRow(lvHwnd, r)
		}
		return r		
	}
	
	; Get List item row
	getListItemRow(ByRef Name) {

		ControlGet, list, list,, SysListView321, % this.hwnd
		Loop, Parse, list, `n
			if(instr(A_LoopField, Name)) {
				Name:=substr(A_LoopField, 1, instr(A_LoopField, "`t")-1)
				return A_Index
			}
		return 0
	}
	
	; ============= TABS =================
	activatePlayback() {
		return this.activateTab(1)
	}
	activateRecording() {
		return this.activateTab(2)
	}
	activateSounds() {
		return this.activateTab(3)
	}
	activateCommunications() {
		return this.activateTab(4)
	}
	activateTab(n) {
		if(tab:=n-this.getTab()) {
			if(tab > 0)
				control, TabRight, % tab, SysTabControl321, % this.hwnd
			else
				control, TabLeft, % tab*-1, SysTabControl321, % this.hwnd
		}
		return !ErrorLevel
	}
	getTab() {
		controlget, tab, tab,, SysTabControl321, % this.hwnd
		return tab
	}
}

class C_PropertiesWindow
{
	static WinTitle:="Properties"
	static classNN:="ComboBox1"
	__New(Name = "") {
		SetTitleMatchMode, 2
		WinWait, % Name:= (Name = "" ? "" : Name " ") this.WinTitle, , 1
		if(ErrorLevel)
			return false
		this.hwnd:="ahk_id" winExist(Name)
		controlget, choice, choice, , % this.classNN, % this.hwnd
		this.choice:=choice
	}
	
	setChoice(choice) {
		if(instr(choice, this.choice))
			return true
		controlget, list, list, , % this.classNN, % this.hwnd
		Loop, Parse, list, `n
			if(instr(A_LoopField, choice))
				i:=A_Index, this.choice:=A_LoopField, break
		control, choose, %i%, % this.classNN, % this.hwnd
		return !ErrorLevel
	}
	Close(save=true) {
		if(save) {
			ControlClick, Button6, % this.hwnd,,, 1
			WinWaitClose, % this.hwnd,, 1
			if(ErrorLevel) {
				ControlClick, Button6, % this.hwnd,,, 1
				WinWaitClose, % this.hwnd,, 1
			}
			return !ErrorLevel
		}
		else
			WinClose, % this.hwnd
		return true
	}
}

; Thanks to just me!
LV_DoubleClickRow(HLV, Row) {
   ; HLV : ListView's HWND, Row : 1-based row number
   HPROC := 0
   MyPID := DllCall("GetCurrentProcessId", "UInt")
   WinGet, LVPID, PID, ahk_id %HLV%
   If !(LVPID)
      Return False
   VarSetCapacity(RECT, 16, 0)
   If (LVPID <> MyPID) {
      If !(HPROC := DllCall("OpenProcess", "UInt", 0x0438, "Int", False, "UInt", LVPID, "Ptr"))
         Return False
      If !(Addr := DllCall("VirtualAllocEx", "Ptr", HPROC, "Ptr", 0, "UPtr", 16, "UInt", 0x1000, "UInt", 4, "UPtr"))
         Return (DllCall("CloseHandle", "Ptr", HPROC) & 0) ; False
   }
   Else
      Addr := &RECT
   SendMessage, 0x1013, % (Row - 1), 1, , ahk_id %HLV% ; LVM_ENSUREVISIBLE
   SendMessage, 0x100E, % (Row - 1), %Addr%, , ahk_id %HLV% ; LVM_GETITEMRECT
   If (HPROC) {
      DllCall("ReadProcessMemory", "Ptr", HPROC, "Ptr", Addr, "Ptr", &RECT, "UPtr", 16, "Ptr", 0)
      DllCall("VirtualFreeEx", "Ptr", HPROC, "Ptr", Addr, "UPtr", 0, "UInt", 0x8000)
      DllCall("CloseHandle", "Ptr", HPROC)
   }
   POINT := NumGet(RECT, 0, "Short") | (NumGet(RECT, 4, "Short") << 16)
   PostMessage, 0x0201, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONDOWN
   PostMessage, 0x0202, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONUP
   PostMessage, 0x0203, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONDBLCLK
   PostMessage, 0x0202, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONUP
   Return True
}

LVSel(WinTitle, r=0)
{
	--r
	VarSetCapacity(LVITEM, 20, 0) ;to receive LVITEM
;	LVIS_FOCUSED:=1   LVIS_SELECTED:=2
	NumPut(1 | 2, LVITEM, 12)  ; state
	NumPut(1 | 2, LVITEM, 16)  ; stateMask
	RemoteBuf_Open(hLVITEM, WinTitle, 20)  ; MASTER_ID = the ahk_id of the process owning the SysListView32 control
	RemoteBuf_Write(hLVITEM, LVITEM,20)
	SendMessage, 0x102B,r,RemoteBuf_Get(hLVITEM), SysListView321,%WinTitle%   ; LVM_SETITEMSTATE:=0x102B
	RemoteBuf_Close(hLVITEM)
}
;   
;	Title:	Remote Buffer
;			*Read and write process memory*
;
/*-------------------------------------------------------------------------------
	Function: Open
			  Open remote buffer

	Parameters:
			H		- Reference to variable to receive remote buffer handle
			hwnd    - HWND of the window that belongs to the process
			size    - Size of the buffer

	Returns:
			Error message on failure
 */
RemoteBuf_Open(ByRef H, WinTitle, size) {
	static MEM_COMMIT=0x1000, PAGE_READWRITE=4
	WinGet, pid, PID, %WinTitle%
	hProc   := DllCall( "OpenProcess", "uint", 0x38, "int", 0, "uint", pid) ;0x38 = PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE
	IfEqual, hProc,0, return A_ThisFunc ">   Unable to open process (" A_LastError ")"
	bufAdr  := DllCall( "VirtualAllocEx", "uint", hProc, "uint", 0, "uint", size, "uint", MEM_COMMIT, "uint", PAGE_READWRITE)
	IfEqual, bufAdr,0, return A_ThisFunc ">   Unable to allocate memory (" A_LastError ")"
	; Buffer handle structure:
	 ;	@0: hProc
	 ;	@4: size
	 ;	@8: bufAdr
	VarSetCapacity(H, 12, 0 )
	NumPut( hProc,	H, 0)
	NumPut( size,	H, 4)
	NumPut( bufAdr, H, 8)
}

/*----------------------------------------------------
	Function: Close
			  Close the remote buffer

	Parameters:
			  H - Remote buffer handle
 */
RemoteBuf_Close(ByRef H) {
	handle := NumGet(H, 0)
	IfEqual, handle, 0, return A_ThisFunc ">   Invalid remote buffer handle"
	adr    := NumGet(H, 8)
	r := DllCall( "VirtualFreeEx", "uint", handle, "uint", adr, "uint", 0, "uint", 0x8000) ; MEM_RELEASE
	ifEqual, r, 0, return A_ThisFunc ">   Unable to free memory (" A_LastError ")"
	DllCall( "CloseHandle", "uint", handle )
	VarSetCapacity(H, 0 )
}

/*----------------------------------------------------
	Function:   Read
				Read from the remote buffer into local buffer

	Parameters:
         H			- Remote buffer handle
         pLocal		- Reference to the local buffer
         pSize		- Size of the local buffer
         pOffset	- Optional reading offset, by default 0

Returns:
         TRUE on success or FALSE on failure. ErrorMessage on bad remote buffer handle
 */
RemoteBuf_Read(ByRef H, ByRef pLocal, pSize, pOffset = 0){
	handle := NumGet( H, 0),   size:= NumGet( H, 4),   adr := NumGet( H, 8)
	IfEqual, handle, 0, return A_ThisFunc ">   Invalid remote buffer handle"
	IfGreaterOrEqual, offset, %size%, return A_ThisFunc ">   Offset is bigger then size"

	VarSetCapacity( pLocal, pSize )
	return DllCall( "ReadProcessMemory", "uint", handle, "uint", adr + pOffset, "uint", &pLocal, "uint", size, "uint", 0 ), VarSetCapacity(pLocal, -1)
}

/*----------------------------------------------------
	Function:   Write
				Write local buffer into remote buffer

	Parameters:
         H			- Remote buffer handle
         pLocal		- Reference to the local buffer
         pSize		- Size of the local buffer
         pOffset	- Optional writting offset, by default 0

	Returns:
         TRUE on success or FALSE on failure. ErrorMessage on bad remote buffer handle
 */
RemoteBuf_Write(Byref H, byref pLocal, pSize, pOffset=0) {
	handle:= NumGet( H, 0),   size := NumGet( H, 4),   adr := NumGet( H, 8)
	IfEqual, handle, 0, return A_ThisFunc ">   Invalid remote buffer handle"
	IfGreaterOrEqual, offset, %size%, return A_ThisFunc ">   Offset is bigger then size"
	return DllCall( "WriteProcessMemory", "uint", handle,"uint", adr + pOffset,"uint", &pLocal,"uint", pSize, "uint", 0 )
}

/*----------------------------------------------------
	Function:   Get
				Get address or size of the remote buffer

	Parameters:
         H		- Remote buffer handle
         pQ     - Query parameter: set to "adr" to get address (default), to "size" to get the size or to "handle" to get Windows API handle of the remote buffer.

	Returns:
         Address or size of the remote buffer
 */
RemoteBuf_Get(ByRef H, pQ="adr") {
	return pQ = "adr" ? NumGet(H, 8) : pQ = "size" ? NumGet(H, 4) : NumGet(H)
}
monorchid

Re: Disable, then re enable a microphone after coming out of sleep

10 Mar 2016, 20:00

It needs to disable the device first, then enable it; this is not for testing purposes.

More in depth:

The problem I face is that upon coming out of sleep, my microphone stops working. Its not DISABLED per se, but it just does nothing. It does not capture audio, it does not spit an error or anything, it just stops working. Corsair has no idea why this is(and its past warranty.) so I'm stuck either restarting teamspeak 3, or disabling THEN re enabling the microphone(fixes all the issues, usually.)

As for the closing issue, its still there.

The only thing I can think of is I use an application called Displayfusion that gives me a second taskbar on my 2nd monitor as well as hook into other windows to add move to other monitor buttons. I tried disabling those buttons and everything from running for this... In this case, mmsys.cpl is run by Rundl32.exe. However, this did not fix the issue for me. Do you have any other suggestions? I really rather not get rid of displayfusion, but if I must I can go back to ultramon.

Sorry for the bad explanation before and all the trouble, but I gotta say your code gets more complex/beautiful with each rendition lol
wizardzedd
Posts: 319
Joined: 23 Jan 2016, 23:03

Re: Disable, then re enable a microphone after coming out of sleep

10 Mar 2016, 22:08

I see now, so using the code I wrote before you would basically have to set the property 2 times (couldn't just hit apply since it removes the device when disabled.) I decided to try a different approach that uses the context menu that hopefully will be simpler and work better.

Code: Select all

#SingleInstance, force 
device:="Microphone" ; change to your device
sounds:=new C_Sounds()	; Sounds window
sounds.activateRecording()	; Activate Recording Tab
myMenu:=sounds.openMenu(device)	; Open menu of device
myMenu.ClickText("disable")
myMenu:=sounds.openMenu(device)
myMenu.ClickText("enable")
sounds.Close()
return

class C_Sounds	
{
	static winTitle:="Sound"
	__New() {
		if(!this.hwnd:=WinExist(WinTitle))
			this.hwnd:=this.Open()
		if(!this.hwnd)
			MsgBox, 16, , % A_ThisFunc "`tFailed to open Sounds" 	
		this.hwnd:="ahk_id" this.hwnd
	}
	; Open
	Open() {		
		Run, %ComSpec% /C control mmsys.cpl sounds
		WinWait, % this.winTitle,, 3
		return WinExist(this.WinTitle)
	}
	; Close
	Close() {
		WinClose, % this.hwnd
	}
	
	; =============================== LISTVIEW =============================
	; Open Context Menu
	openMenu(Name="") {
		if(this.rightClickListItem(Name)) {
			WinWait, % C_StandardMenu.WinTitle,, 1
			if(!ErrorLevel)
				return new C_StandardMenu()
		} 
		MsgBox, 16, , % A_ThisFunc "`tFailed to open menu for " Name	
		return false
	}
	
	; Select ListView Item
	selectListItem(ByRef Name) {
		if(r:=this.getListItemRow(Name)) 
			LVSel(this.hwnd, r)
		return r
	}
	
	RightClickListItem(ByRef Name) {
		if(r:=this.getListItemRow(Name)) {
			controlget, lvHwnd, hwnd,, SysListView321, % this.hwnd
			if(!lvHwnd)
				MsgBox, 16, , % A_ThisFunc "`tFailed to get listview SysListView321 handle"
			LV_rightClickRow(lvHwnd, r)
		}
		return r		
	}
	
	; Get List item row
	getListItemRow(ByRef Name) {
		ControlGet, list, list,, SysListView321, % this.hwnd
		Loop, Parse, list, `n
			if(instr(A_LoopField, Name)) {
				Name:=substr(A_LoopField, 1, instr(A_LoopField, "`t")-1)
				return A_Index
			}
		MsgBox, 16, , % A_ThisFunc "`tFailed to find listview item " Name
		return 0
	}
	
	; ============= TABS =================
	activatePlayback() {
		return this.activateTab(1)
	}
	activateRecording() {
		return this.activateTab(2)
	}
	activateSounds() {
		return this.activateTab(3)
	}
	activateCommunications() {
		return this.activateTab(4)
	}
	activateTab(n) {
		if(tab:=n-this.getTab()) {
			if(tab > 0)
				control, TabRight, % tab, SysTabControl321, % this.hwnd
			else
				control, TabLeft, % tab*-1, SysTabControl321, % this.hwnd
		}
		return !ErrorLevel
	}
	getTab() {
		controlget, tab, tab,, SysTabControl321, % this.hwnd
		return tab
	}
}

class C_StandardMenu
{
	static winTitle:="ahk_class #32768"
	__New() {
		WinGet, cTitle, id, % this.winTitle
		if(!cTitle)
			return false
		SendMessage, 0x01E1, , , , % this.title:="ahk_id" cTitle  ;Retrieve menu handle from window
		this.hMenu:=ErrorLevel
		this.getCount() ; initialize count
	}

; Click Menu item with text "Text" in it.
	ClickText(Text) {
		return (p:=this.getItemPos(Text)) ? this.ClickMenuItem(p) : false
	}
		
	ClickMenuItem(pos) {
		VarSetCapacity(Rect, 16, 0)
		if(!Dllcall("user32.dll\GetMenuItemRect", "UInt", substr(this.title, 7), "UInt", this.hMenu, "UInt", pos-1, "Ptr", &Rect ))
			return false
		POINT := NumGet(Rect, 0, "Short") | NumGet(Rect, 4, "Short") << 16
		PostMessage, 0x0201, 0, POINT, , % this.title ; WM_LBUTTONDOWN
		PostMessage, 0x0202, 0, POINT, , % this.title ; WM_LBUTTONUP
		return true
	}
	; ===================================================================
	; ======================== GETTERS ==================================
	; ===================================================================
	; Get Item count
	getCount() {
		Return this.Count:=DllCall("GetMenuItemCount",UInt, this.hMenu)
	}
	; Get Selected
	getSelected() { 
		Loop, % this.Count
		{
			(t:=new this.C_MenuItemInfo(A_Index)).GetContextMenuState(this.hMenu)
			if(t.isSelected())
				return A_Index
		}
	}
	
	getItemPos(Text) {
		Loop, % this.Count
			if(instr((new this.C_MenuItemInfo(A_Index)).GetContextMenuText(this.hMenu), Text))
				return A_Index
	}
	
	getText(pos) {
		return (new this.C_MenuItemInfo(pos)).GetContextMenuText(this.hMenu)
	}
	
	getChecked(pos) {
		(t:=new this.C_MenuItemInfo(pos)).GetContextMenuState()
		return t.isChecked()
	}
	
	getEnabled(pos) {
		(t:=new this.C_MenuItemInfo(pos)).GetContextMenuState()
		return t.IsEnabled()
	}
	
	getDefault() {
		Loop, % this.Count
		{
			(t:=new this.C_MenuItemInfo(A_Index)).GetContextMenuState(this.hMenu)
			if(t.isDefault())
				return A_Index
		}	
	}
		
	; C_MenuItemInfo
	class C_MenuItemInfo
	{
		static cbSize := 48
		__New(pos){	
			if pos is not number
				pos:=1
			pos > 0 ? this.pos:=pos : this.pos:=1
		}
		isChecked() {
			return this.info & 0x8
		}
		IsEnabled() {
			return (!(this.info & 0x3))
		}
		isSelected() {
			return this.info & 0x80
		}
		isDefault() {
			return this.info & 0x1000
		}
		
		GetContextMenuState(hMenu) {
		  VarSetCapacity(MenuItemInfo, 60, 0)   ;We need to allocate a struct 60
		  NumPut(this.cbSize, MenuItemInfo, 0)   ;Set Size of Struct to the first member
		  NumPut(1, MenuItemInfo, 4)   ;Get only Flags from dllcall GetMenuItemInfo MIIM_TYPE = 1
		  DllCall("user32.dll\GetMenuItemInfo",UInt, hMenu, Uint, this.pos-1, uint, 1, "int", &MenuItemInfo)
		  return (ErrorLevel || A_LastError) ? -1 : this.info:= NumGet(MenuItemInfo, 12)  ; fState
		}
		
		GetContextMenuText(hMenu) {
		  VarSetCapacity(MenuItemInfo, 200, 0)
		   NumPut(this.cbSize, MenuItemInfo, 0)  ;Set Size of Struct (48) to the first member
		  NumPut(64, MenuItemInfo, 4)   ;Retrieve string MIIM_STRING = 0x40 = 64 (/ MIIM_TYPE = 0x10 = 16)
		  if(DllCall("user32.dll\GetMenuItemInfo",UInt, hMenu, Uint, this.pos-1, uint, 1, "int", &MenuItemInfo) = 0 
			|| ErrorLevel || A_LastError || (GetMenuItemInfoRes := NumGet(MenuItemInfo, 40)) = 0) ;Get size of string from struct
			 return -1
		  GetMenuItemInfoRes += 2
		  VarSetCapacity(PopupText, GetMenuItemInfoRes, 0)  ;Set capacity of string that will be filled by windows
		  NumPut(GetMenuItemInfoRes, MenuItemInfo, 40, 4)    ;Set Size plus 0 terminator + security ;-)
		  NumPut(&PopupText, MenuItemInfo, 36, 4)
		  return (DllCall("user32.dll\GetMenuItemInfo",UInt, hMenu, Uint, this.pos-1, uint, 1, "int", &MenuItemInfo) = 0		
			|| ErrorLevel || A_LastError) ? -1 : this.Text:=PopupText
		}
	}
}

; Thanks to just me!
LV_RightClickRow(HLV, Row) {
   ; HLV : ListView's HWND, Row : 1-based row number
   HPROC := 0
   MyPID := DllCall("GetCurrentProcessId", "UInt")
   WinGet, LVPID, PID, ahk_id %HLV%
   If !(LVPID)
      Return False
   VarSetCapacity(RECT, 16, 0)
   If (LVPID <> MyPID) {
      If !(HPROC := DllCall("OpenProcess", "UInt", 0x0438, "Int", False, "UInt", LVPID, "Ptr"))
         Return False
      If !(Addr := DllCall("VirtualAllocEx", "Ptr", HPROC, "Ptr", 0, "UPtr", 16, "UInt", 0x1000, "UInt", 4, "UPtr"))
         Return (DllCall("CloseHandle", "Ptr", HPROC) & 0) ; False
   }
   Else
      Addr := &RECT
   SendMessage, 0x1013, % (Row - 1), 1, , ahk_id %HLV% ; LVM_ENSUREVISIBLE
   SendMessage, 0x100E, % (Row - 1), %Addr%, , ahk_id %HLV% ; LVM_GETITEMRECT
   If (HPROC) {
      DllCall("ReadProcessMemory", "Ptr", HPROC, "Ptr", Addr, "Ptr", &RECT, "UPtr", 16, "Ptr", 0)
      DllCall("VirtualFreeEx", "Ptr", HPROC, "Ptr", Addr, "UPtr", 0, "UInt", 0x8000)
      DllCall("CloseHandle", "Ptr", HPROC)
   }
   POINT := (x:=NumGet(RECT, 0, "Short")) | ((y:=NumGet(RECT, 4, "Short")) << 16)
   sleep, 1000
   PostMessage, 0x0201, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONDOWN
   PostMessage, 0x0202, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONDOWN
   send, {AppsKey}
Return True
}
monorchid

Re: Disable, then re enable a microphone after coming out of sleep

10 Mar 2016, 22:25

monorchid wrote:There is an error in line 48, "LVsel(this.hwnd,r)

fatal error.

:O

To be exact, its a call to nonexistant function, mb
wizardzedd
Posts: 319
Joined: 23 Jan 2016, 23:03

Re: Disable, then re enable a microphone after coming out of sleep

10 Mar 2016, 22:36

oops, thats what happens when you cut out parts of code xD.

Code: Select all

;
; AutoHotkey Version: 1.1.23.01
; Language:       English
; Platform:       Windows 10
; Author:         WizardZedd
;
; Script Function:
;	
;

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance, force		; Don't worry about annoying messages.
#Include %a_scriptdir%
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
device:="Microphone" ; change to your device
sounds:=new C_Sounds()	; Sounds window
sounds.activateRecording()	; Activate Recording Tab
myMenu:=sounds.openMenu(device)	; Open menu of device
myMenu.ClickText("disable")
myMenu:=sounds.openMenu(device)
myMenu.ClickText("enable")
sounds.Close()
return
 
class C_Sounds	
{
	static winTitle:="Sound"
	__New() {
		if(!this.hwnd:=WinExist(WinTitle))
			this.hwnd:=this.Open()
		if(!this.hwnd)
			MsgBox, 16, , % A_ThisFunc "`tFailed to open Sounds" 	
		this.hwnd:="ahk_id" this.hwnd
	}
	; Open
	Open() {		
		Run, %ComSpec% /C control mmsys.cpl sounds
		WinWait, % this.winTitle,, 3
		return WinExist(this.WinTitle)
	}
	; Close
	Close() {
		WinClose, % this.hwnd
	}
 
	; =============================== LISTVIEW =============================
	; Open Context Menu
	openMenu(Name="") {
		if(this.rightClickListItem(Name)) {
			WinWait, % C_StandardMenu.WinTitle,, 1
			if(!ErrorLevel)
				return new C_StandardMenu()
		} 
		MsgBox, 16, , % A_ThisFunc "`tFailed to open menu for " Name	
		return false
	}
 
	RightClickListItem(ByRef Name) {
		if(r:=this.getListItemRow(Name)) {
			controlget, lvHwnd, hwnd,, SysListView321, % this.hwnd
			if(!lvHwnd)
				MsgBox, 16, , % A_ThisFunc "`tFailed to get listview SysListView321 handle"
			LV_rightClickRow(lvHwnd, r)
		}
		return r		
	}
 
	; Get List item row
	getListItemRow(ByRef Name) {
		ControlGet, list, list,, SysListView321, % this.hwnd
		Loop, Parse, list, `n
			if(instr(A_LoopField, Name)) {
				Name:=substr(A_LoopField, 1, instr(A_LoopField, "`t")-1)
				return A_Index
			}
		MsgBox, 16, , % A_ThisFunc "`tFailed to find listview item " Name
		return 0
	}
 
	; ============= TABS =================
	activatePlayback() {
		return this.activateTab(1)
	}
	activateRecording() {
		return this.activateTab(2)
	}
	activateSounds() {
		return this.activateTab(3)
	}
	activateCommunications() {
		return this.activateTab(4)
	}
	activateTab(n) {
		if(tab:=n-this.getTab()) {
			if(tab > 0)
				control, TabRight, % tab, SysTabControl321, % this.hwnd
			else
				control, TabLeft, % tab*-1, SysTabControl321, % this.hwnd
		}
		return !ErrorLevel
	}
	getTab() {
		controlget, tab, tab,, SysTabControl321, % this.hwnd
		return tab
	}
}
 
class C_StandardMenu
{
	static winTitle:="ahk_class #32768"
	__New() {
		WinGet, cTitle, id, % this.winTitle
		if(!cTitle)
			return false
		SendMessage, 0x01E1, , , , % this.title:="ahk_id" cTitle  ;Retrieve menu handle from window
		this.hMenu:=ErrorLevel
		this.getCount() ; initialize count
	}
 
; Click Menu item with text "Text" in it.
	ClickText(Text) {
		return (p:=this.getItemPos(Text)) ? this.ClickMenuItem(p) : false
	}
 
	ClickMenuItem(pos) {
		VarSetCapacity(Rect, 16, 0)
		if(!Dllcall("user32.dll\GetMenuItemRect", "UInt", substr(this.title, 7), "UInt", this.hMenu, "UInt", pos-1, "Ptr", &Rect ))
			return false
		POINT := NumGet(Rect, 0, "Short") | NumGet(Rect, 4, "Short") << 16
		PostMessage, 0x0201, 0, POINT, , % this.title ; WM_LBUTTONDOWN
		PostMessage, 0x0202, 0, POINT, , % this.title ; WM_LBUTTONUP
		return true
	}
	; ===================================================================
	; ======================== GETTERS ==================================
	; ===================================================================
	; Get Item count
	getCount() {
		Return this.Count:=DllCall("GetMenuItemCount",UInt, this.hMenu)
	}
	; Get Selected
	getSelected() { 
		Loop, % this.Count
		{
			(t:=new this.C_MenuItemInfo(A_Index)).GetContextMenuState(this.hMenu)
			if(t.isSelected())
				return A_Index
		}
	}
 
	getItemPos(Text) {
		Loop, % this.Count
			if(instr((new this.C_MenuItemInfo(A_Index)).GetContextMenuText(this.hMenu), Text))
				return A_Index
	}
 
	getText(pos) {
		return (new this.C_MenuItemInfo(pos)).GetContextMenuText(this.hMenu)
	}
 
	getChecked(pos) {
		(t:=new this.C_MenuItemInfo(pos)).GetContextMenuState()
		return t.isChecked()
	}
 
	getEnabled(pos) {
		(t:=new this.C_MenuItemInfo(pos)).GetContextMenuState()
		return t.IsEnabled()
	}
 
	getDefault() {
		Loop, % this.Count
		{
			(t:=new this.C_MenuItemInfo(A_Index)).GetContextMenuState(this.hMenu)
			if(t.isDefault())
				return A_Index
		}	
	}
 
	; C_MenuItemInfo
	class C_MenuItemInfo
	{
		static cbSize := 48
		__New(pos){	
			if pos is not number
				pos:=1
			pos > 0 ? this.pos:=pos : this.pos:=1
		}
		isChecked() {
			return this.info & 0x8
		}
		IsEnabled() {
			return (!(this.info & 0x3))
		}
		isSelected() {
			return this.info & 0x80
		}
		isDefault() {
			return this.info & 0x1000
		}
 
		GetContextMenuState(hMenu) {
		  VarSetCapacity(MenuItemInfo, 60, 0)   ;We need to allocate a struct 60
		  NumPut(this.cbSize, MenuItemInfo, 0)   ;Set Size of Struct to the first member
		  NumPut(1, MenuItemInfo, 4)   ;Get only Flags from dllcall GetMenuItemInfo MIIM_TYPE = 1
		  DllCall("user32.dll\GetMenuItemInfo",UInt, hMenu, Uint, this.pos-1, uint, 1, "int", &MenuItemInfo)
		  return (ErrorLevel || A_LastError) ? -1 : this.info:= NumGet(MenuItemInfo, 12)  ; fState
		}
 
		GetContextMenuText(hMenu) {
		  VarSetCapacity(MenuItemInfo, 200, 0)
		   NumPut(this.cbSize, MenuItemInfo, 0)  ;Set Size of Struct (48) to the first member
		  NumPut(64, MenuItemInfo, 4)   ;Retrieve string MIIM_STRING = 0x40 = 64 (/ MIIM_TYPE = 0x10 = 16)
		  if(DllCall("user32.dll\GetMenuItemInfo",UInt, hMenu, Uint, this.pos-1, uint, 1, "int", &MenuItemInfo) = 0 
			|| ErrorLevel || A_LastError || (GetMenuItemInfoRes := NumGet(MenuItemInfo, 40)) = 0) ;Get size of string from struct
			 return -1
		  GetMenuItemInfoRes += 2
		  VarSetCapacity(PopupText, GetMenuItemInfoRes, 0)  ;Set capacity of string that will be filled by windows
		  NumPut(GetMenuItemInfoRes, MenuItemInfo, 40, 4)    ;Set Size plus 0 terminator + security ;-)
		  NumPut(&PopupText, MenuItemInfo, 36, 4)
		  return (DllCall("user32.dll\GetMenuItemInfo",UInt, hMenu, Uint, this.pos-1, uint, 1, "int", &MenuItemInfo) = 0		
			|| ErrorLevel || A_LastError) ? -1 : this.Text:=PopupText
		}
	}
}
 
; Thanks to just me!
LV_RightClickRow(HLV, Row) {
   ; HLV : ListView's HWND, Row : 1-based row number
   HPROC := 0
   MyPID := DllCall("GetCurrentProcessId", "UInt")
   WinGet, LVPID, PID, ahk_id %HLV%
   If !(LVPID)
      Return False
   VarSetCapacity(RECT, 16, 0)
   If (LVPID <> MyPID) {
      If !(HPROC := DllCall("OpenProcess", "UInt", 0x0438, "Int", False, "UInt", LVPID, "Ptr"))
         Return False
      If !(Addr := DllCall("VirtualAllocEx", "Ptr", HPROC, "Ptr", 0, "UPtr", 16, "UInt", 0x1000, "UInt", 4, "UPtr"))
         Return (DllCall("CloseHandle", "Ptr", HPROC) & 0) ; False
   }
   Else
      Addr := &RECT
   SendMessage, 0x1013, % (Row - 1), 1, , ahk_id %HLV% ; LVM_ENSUREVISIBLE
   SendMessage, 0x100E, % (Row - 1), %Addr%, , ahk_id %HLV% ; LVM_GETITEMRECT
   If (HPROC) {
      DllCall("ReadProcessMemory", "Ptr", HPROC, "Ptr", Addr, "Ptr", &RECT, "UPtr", 16, "Ptr", 0)
      DllCall("VirtualFreeEx", "Ptr", HPROC, "Ptr", Addr, "UPtr", 0, "UInt", 0x8000)
      DllCall("CloseHandle", "Ptr", HPROC)
   }
   POINT := (x:=NumGet(RECT, 0, "Short")) | ((y:=NumGet(RECT, 4, "Short")) << 16)
   sleep, 1000
   PostMessage, 0x0201, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONDOWN
   PostMessage, 0x0202, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONDOWN
   send, {AppsKey}
Return True
}
Monorchid
Posts: 20
Joined: 10 Mar 2016, 22:25

Re: Disable, then re enable a microphone after coming out of sleep

10 Mar 2016, 23:30

This time it opens it up as if you right clicked, however it doesn't click enable or disable(nothing happens after this.) if I do it myself, or click out of it, it closes the window as if it were done. Something is going wrong :/.

Is there anything I do can to help? like provide a log or something? If it works on your end it sounds like there is something it just doesn't like about my computer...

I installed autohotkey outside of the normal Program dir, i know some programs don't like that. Is that the problem(my poor SSD must be protected!)
wizardzedd
Posts: 319
Joined: 23 Jan 2016, 23:03

Re: Disable, then re enable a microphone after coming out of sleep

11 Mar 2016, 00:05

Sometimes I wish all systems could be the same lol. The 2 calls in question will be clickMenuItem(pos) and getText(pos). Try running this code with the menu already open, press ctrl-b. What do the 2 message boxes say? .
EDIT: It should say "x is (beginning x position of 2nd menu item) y is (beginning y position of 2nd menu item)". The second should say "Text at position 2 is (whatever's at pos 2)"

Code: Select all

^b::
myMenu:=new C_StandardMenu()
text:=myMenu.getText(2) 
myMenu.ClickMenuItem(2)
MsgBox, % "Text at position 2 is " text	
return
 
class C_Sounds	
{
	static winTitle:="Sound"
	__New() {
		if(!this.hwnd:=WinExist(WinTitle))
			this.hwnd:=this.Open()
		if(!this.hwnd)
			MsgBox, 16, , % A_ThisFunc "`tFailed to open Sounds" 	
		this.hwnd:="ahk_id" this.hwnd
	}
	; Open
	Open() {		
		Run, %ComSpec% /C control mmsys.cpl sounds
		WinWait, % this.winTitle,, 3
		return WinExist(this.WinTitle)
	}
	; Close
	Close() {
		WinClose, % this.hwnd
	}
 
	; =============================== LISTVIEW =============================
	; Open Context Menu
	openMenu(Name="") {
		if(this.rightClickListItem(Name)) {
			WinWait, % C_StandardMenu.WinTitle,, 1
			if(!ErrorLevel)
				return new C_StandardMenu()
		} 
		MsgBox, 16, , % A_ThisFunc "`tFailed to open menu for " Name	
		return false
	}
 
	RightClickListItem(ByRef Name) {
		if(r:=this.getListItemRow(Name)) {
			controlget, lvHwnd, hwnd,, SysListView321, % this.hwnd
			if(!lvHwnd)
				MsgBox, 16, , % A_ThisFunc "`tFailed to get listview SysListView321 handle"
			LV_rightClickRow(lvHwnd, r)
		}
		return r		
	}
 
	; Get List item row
	getListItemRow(ByRef Name) {
		ControlGet, list, list,, SysListView321, % this.hwnd
		Loop, Parse, list, `n
			if(instr(A_LoopField, Name)) {
				Name:=substr(A_LoopField, 1, instr(A_LoopField, "`t")-1)
				return A_Index
			}
		MsgBox, 16, , % A_ThisFunc "`tFailed to find listview item " Name
		return 0
	}
 
	; ============= TABS =================
	activatePlayback() {
		return this.activateTab(1)
	}
	activateRecording() {
		return this.activateTab(2)
	}
	activateSounds() {
		return this.activateTab(3)
	}
	activateCommunications() {
		return this.activateTab(4)
	}
	activateTab(n) {
		if(tab:=n-this.getTab()) {
			if(tab > 0)
				control, TabRight, % tab, SysTabControl321, % this.hwnd
			else
				control, TabLeft, % tab*-1, SysTabControl321, % this.hwnd
		}
		return !ErrorLevel
	}
	getTab() {
		controlget, tab, tab,, SysTabControl321, % this.hwnd
		return tab
	}
}
 
class C_StandardMenu
{
	static winTitle:="ahk_class #32768"
	__New() {
		WinGet, cTitle, id, % this.winTitle
		if(!cTitle)
			return false
		SendMessage, 0x01E1, , , , % this.title:="ahk_id" cTitle  ;Retrieve menu handle from window
		this.hMenu:=ErrorLevel
		this.getCount() ; initialize count
	}
 
; Click Menu item with text "Text" in it.
	ClickText(Text) {
		return (p:=this.getItemPos(Text)) ? this.ClickMenuItem(p) : false
	}
 
	ClickMenuItem(pos) {
		VarSetCapacity(Rect, 16, 0)
		if(!Dllcall("user32.dll\GetMenuItemRect", "UInt", substr(this.title, 7), "UInt", this.hMenu, "UInt", pos-1, "Ptr", &Rect ))
			return false
		POINT := (x:=NumGet(Rect, 0, "Short")) | (y:=NumGet(Rect, 4, "Short")) << 16
		PostMessage, 0x0201, 0, POINT, , % this.title ; WM_LBUTTONDOWN
		PostMessage, 0x0202, 0, POINT, , % this.title ; WM_LBUTTONUP
		MsgBox, % "x is " x " y is " y
		return true
	}
	; ===================================================================
	; ======================== GETTERS ==================================
	; ===================================================================
	; Get Item count
	getCount() {
		Return this.Count:=DllCall("GetMenuItemCount",UInt, this.hMenu)
	}
	; Get Selected
	getSelected() { 
		Loop, % this.Count
		{
			(t:=new this.C_MenuItemInfo(A_Index)).GetContextMenuState(this.hMenu)
			if(t.isSelected())
				return A_Index
		}
	}
 
	getItemPos(Text) {
		Loop, % this.Count
			if(instr((new this.C_MenuItemInfo(A_Index)).GetContextMenuText(this.hMenu), Text))
				return A_Index
	}
 
	getText(pos) {
		return (new this.C_MenuItemInfo(pos)).GetContextMenuText(this.hMenu)
	}
 
	getChecked(pos) {
		(t:=new this.C_MenuItemInfo(pos)).GetContextMenuState()
		return t.isChecked()
	}
 
	getEnabled(pos) {
		(t:=new this.C_MenuItemInfo(pos)).GetContextMenuState()
		return t.IsEnabled()
	}
 
	getDefault() {
		Loop, % this.Count
		{
			(t:=new this.C_MenuItemInfo(A_Index)).GetContextMenuState(this.hMenu)
			if(t.isDefault())
				return A_Index
		}	
	}
 
	; C_MenuItemInfo
	class C_MenuItemInfo
	{
		static cbSize := 48
		__New(pos){	
			if pos is not number
				pos:=1
			pos > 0 ? this.pos:=pos : this.pos:=1
		}
		isChecked() {
			return this.info & 0x8
		}
		IsEnabled() {
			return (!(this.info & 0x3))
		}
		isSelected() {
			return this.info & 0x80
		}
		isDefault() {
			return this.info & 0x1000
		}
 
		GetContextMenuState(hMenu) {
		  VarSetCapacity(MenuItemInfo, 60, 0)   ;We need to allocate a struct 60
		  NumPut(this.cbSize, MenuItemInfo, 0)   ;Set Size of Struct to the first member
		  NumPut(1, MenuItemInfo, 4)   ;Get only Flags from dllcall GetMenuItemInfo MIIM_TYPE = 1
		  DllCall("user32.dll\GetMenuItemInfo",UInt, hMenu, Uint, this.pos-1, uint, 1, "int", &MenuItemInfo)
		  return (ErrorLevel || A_LastError) ? -1 : this.info:= NumGet(MenuItemInfo, 12)  ; fState
		}
 
		GetContextMenuText(hMenu) {
		  VarSetCapacity(MenuItemInfo, 200, 0)
		   NumPut(this.cbSize, MenuItemInfo, 0)  ;Set Size of Struct (48) to the first member
		  NumPut(64, MenuItemInfo, 4)   ;Retrieve string MIIM_STRING = 0x40 = 64 (/ MIIM_TYPE = 0x10 = 16)
		  if(DllCall("user32.dll\GetMenuItemInfo",UInt, hMenu, Uint, this.pos-1, uint, 1, "int", &MenuItemInfo) = 0 
			|| ErrorLevel || A_LastError || (GetMenuItemInfoRes := NumGet(MenuItemInfo, 40)) = 0) ;Get size of string from struct
			 return -1
		  GetMenuItemInfoRes += 2
		  VarSetCapacity(PopupText, GetMenuItemInfoRes, 0)  ;Set capacity of string that will be filled by windows
		  NumPut(GetMenuItemInfoRes, MenuItemInfo, 40, 4)    ;Set Size plus 0 terminator + security ;-)
		  NumPut(&PopupText, MenuItemInfo, 36, 4)
		  return (DllCall("user32.dll\GetMenuItemInfo",UInt, hMenu, Uint, this.pos-1, uint, 1, "int", &MenuItemInfo) = 0		
			|| ErrorLevel || A_LastError) ? -1 : this.Text:=PopupText
		}
	}
}
 
; Thanks to just me!
LV_RightClickRow(HLV, Row) {
   ; HLV : ListView's HWND, Row : 1-based row number
   HPROC := 0
   MyPID := DllCall("GetCurrentProcessId", "UInt")
   WinGet, LVPID, PID, ahk_id %HLV%
   If !(LVPID)
      Return False
   VarSetCapacity(RECT, 16, 0)
   If (LVPID <> MyPID) {
      If !(HPROC := DllCall("OpenProcess", "UInt", 0x0438, "Int", False, "UInt", LVPID, "Ptr"))
         Return False
      If !(Addr := DllCall("VirtualAllocEx", "Ptr", HPROC, "Ptr", 0, "UPtr", 16, "UInt", 0x1000, "UInt", 4, "UPtr"))
         Return (DllCall("CloseHandle", "Ptr", HPROC) & 0) ; False
   }
   Else
      Addr := &RECT
   SendMessage, 0x1013, % (Row - 1), 1, , ahk_id %HLV% ; LVM_ENSUREVISIBLE
   SendMessage, 0x100E, % (Row - 1), %Addr%, , ahk_id %HLV% ; LVM_GETITEMRECT
   If (HPROC) {
      DllCall("ReadProcessMemory", "Ptr", HPROC, "Ptr", Addr, "Ptr", &RECT, "UPtr", 16, "Ptr", 0)
      DllCall("VirtualFreeEx", "Ptr", HPROC, "Ptr", Addr, "UPtr", 0, "UInt", 0x8000)
      DllCall("CloseHandle", "Ptr", HPROC)
   }
   POINT := (x:=NumGet(RECT, 0, "Short")) | ((y:=NumGet(RECT, 4, "Short")) << 16)
   sleep, 1000
   PostMessage, 0x0201, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONDOWN
   PostMessage, 0x0202, 0, POINT, , ahk_id %HLV% ; WM_LBUTTONDOWN
   send, {AppsKey}
Return True
}
Monorchid
Posts: 20
Joined: 10 Mar 2016, 22:25

Re: Disable, then re enable a microphone after coming out of sleep

11 Mar 2016, 00:24

x is 353 y is 361
text at position 2 is -1

this seems to poll the mouse location, which is always a little different each time i run it. I assume it has no real bearing on the script besides being semi close?

This is letting windows decide where to open my sound window, and then right clicking microphone and then pressing CTRL+B.
lblb
Posts: 190
Joined: 30 Sep 2013, 11:31

Re: Disable, then re enable a microphone after coming out of sleep

11 Mar 2016, 00:31

Hi,

Since you are encountering issues with clicking the Sound window and stuff, perhaps you could try to re-enable the device more directly by editing the Windows registry? See:
https://smulpuru.wordpress.com/tag/disable-microphone/

Try to find your mic among the devices here: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio. To do that, just click on the folders with the long names in curly brackets: one of them should have the key DeviceState with a value of 0x00000001. If your mic is enabled, that should be it. To verify that this device is indeed your mic, expand the folder with the long name in brackets, look in the Properties subfolder and somewhere near the end of list of keys one of them should be the exact user friendly name of the mic that you see in the Sound panel.

When your mic gets disabled, does the DeviceState value get changed to something other than 0x00000001? If yes, I think you can just re-give it a value of 1 to automatically re-enable it (using AHK of course!)

Sorry I don't have more time to write a code... Hope this helps!
Monorchid
Posts: 20
Joined: 10 Mar 2016, 22:25

Re: Disable, then re enable a microphone after coming out of sleep

11 Mar 2016, 00:53

lblb wrote:Hi,

Since you are encountering issues with clicking the Sound window and stuff, perhaps you could try to re-enable the device more directly by editing the Windows registry? See:
https://smulpuru.wordpress.com/tag/disable-microphone/

Try to find your mic among the devices here: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio. To do that, just click on the folders with the long names in curly brackets: one of them should have the key DeviceState with a value of 0x00000001. If your mic is enabled, that should be it. To verify that this device is indeed your mic, expand the folder with the long name in brackets, look in the Properties subfolder and somewhere near the end of list of keys one of them should be the exact user friendly name of the mic that you see in the Sound panel.

When your mic gets disabled, does the DeviceState value get changed to something other than 0x00000001? If yes, I think you can just re-give it a value of 1 to automatically re-enable it (using AHK of course!)

Sorry I don't have more time to write a code... Hope this helps!
Thanks for the suggestion!

I tested out this idea, and I am sure I found the right microphone key. It does NOT deactivate according to regedit, and changing it from its off value(when manually deactivated) of 10000001, it will not turn back on. If 10000001 is reapplied, and then the microphone is reactivated via Sound, it works just fine again.
lblb
Posts: 190
Joined: 30 Sep 2013, 11:31

Re: Disable, then re enable a microphone after coming out of sleep

11 Mar 2016, 01:04

Well, it was worth a try... But to be sure:

When it's enabled, the value is 00000001 and not 10000001. So if it's disabled, the value is 10000001. Then if you double-click on DeviceState and just write 1 for value data, you don't see it as enabled if you relaunch Sound?

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: aitaixy, Anput, dangoscrub, Google [Bot], joedf, Nerafius and 176 guests