StrokesPlus Forum
                       
StrokesPlus Forum
Home | Profile | Register | Active Topics
Members | Search | FAQ
Username:
Password:
Save Password
Forgot your Password?

 All Forums
 General Discussion
 General Discussion
 How to get elements of window?
 New Topic  Reply to Topic
 Printer Friendly
Author Previous Topic Topic Next Topic  

Samsiline

Germany
3 Posts

Posted - 02/18/2016 :  01:00:10  Show Profile  Reply with Quote
Hi there,

is there a way to get the class names of all elements of a window (e.g. buttons) and check if a specific element is activated?

I want to toggle my default sound output. It works as long as I toggle to the inactive output, but if I choose the sound output which is already active, my sequence of acSendKeys doesnīt correspond to the active buttons.


Hereīs my code:
-- INTERNAL SOUND OUTPUT
--Open sound Control Panel applet
acRunProgram("c:\\windows\\system32\\rundll32.exe","shell32.dll,Control_RunDLL mmsys.cpl,,0",0, 1)
-- activate it (found class name by an other program)
acActivateWindow("#32770")
-- press some keys in a specific sequence
acDelay(200)
acSendKeys("{DOWN}")
acDelay(200)
acSendKeys("{DOWN}")
acDelay(200)
acSendKeys("{TAB}")
acDelay(200)
acSendKeys("{TAB}")
acDelay(200)
acSendKeys("{ENTER}")
acDelay(200)
acSendKeys("{TAB}")
acDelay(200)
acSendKeys("{TAB}")
acDelay(200)
acSendKeys("{TAB}")
acDelay(200)
acSendKeys("{ENTER}")

-- EXTERNAL SOUND OUTPUT
acRunProgram("c:\\windows\\system32\\rundll32.exe","shell32.dll,Control_RunDLL mmsys.cpl,,0",0, 1)
acActivateWindow("#32770")
acDelay(200)
acSendKeys("{DOWN}")
acDelay(200)
acSendKeys("{TAB}")
acDelay(200)
acSendKeys("{ENTER}")
acDelay(200)
acSendKeys("{TAB}")
acDelay(200)
acSendKeys("{TAB}")
acDelay(200)
acSendKeys("{ENTER}")

(It only works if external sound output is first, internal sound output is second item in the sound control panel applet)

Now I want to check if the button "as default" is activated.
If it is acivated, go to it and send enter, if not, go to next sound output item and set this as default (for two outputs it should work).

Any suggestions?

P.S. I know that thereīs a way to toggle the default sound output by Autohotkey, but I want to execute it by Strokesplus,




Rob

USA
2573 Posts

Posted - 02/19/2016 :  22:35:22  Show Profile  Visit Rob's Homepage  Reply with Quote
Unfortunately, I can get pretty close, but S+ doesn't have a function for EnumChildWindows. You might be able to define GetWindow via alien and call it in a loop until you find the button, then check to see if it's disabled, but I don't have the time at the moment to try to put that together.

However, because I'd like to at least have what snippets are available in case I could figure out how to make something work, here's what I have:

First define this in Global Lua:

--This function gets the styles for the window, so you can test if it's disabled, for example
function spGetWinStyle(hwnd, x, y)
if hwnd == nil then hwnd = acGetOwnerWindowByPoint(x, y) end
local user32 = alien.core.load("user32.dll")
local GetWindowLong = user32.GetWindowLongA
GetWindowLong:types{ ret = 'uint', abi = 'stdcall', 'ulong', 'long'}
return GetWindowLong(hwnd, GWL_STYLE)
end


--in your action script:

WINDOW_HANDLE_GOES_HERE = SomeWayToFindTheButton --This is the part that's missing..

--This code would call the above function to get the window style
if bit32.band(spGetWinStyle(WINDOW_HANDLE_GOES_HERE, 0, 0, true), 134217728) == 134217728 then --134217728 = WS_DISABLED
acMessageBox("Button is disabled")
else
acMessageBox("Button is enabled")
end

Apparently, it's possible to call GetWindow in a recursive manner until you found the button (could check by Control ID and caption, they are always the same on my system), but it gets a bit tricky. Ideally, I need to update S+ to allow you to pass in a parent window (the Sound window handle) and get all child windows, then you could loop through until you found the button and the rest is easy. However, my time is a bit limited right now, so it may be a while until I could get around to it.
Go to Top of Page

Rob

USA
2573 Posts

Posted - 02/19/2016 :  23:22:13  Show Profile  Visit Rob's Homepage  Reply with Quote
Okay, so it didn't really take me very long

However, I'm not bothering with updating all of the documentation right now, just releasing the code!

Here's the script that works for me in S+ 2.8.6.2:
acRunProgram("c:\\windows\\system32\\rundll32.exe","shell32.dll,Control_RunDLL mmsys.cpl,,0",0, 1) 
acDelay(1000) --Wait for window to load
sndhwnd = acFindWindow(nil,"Sound") --Works for me on Windows 10
acActivateWindow(sndhwnd)
acGetChildWindows(sndhwnd)
for num, handle in pairs(sp_all_child_windows) do 
	if acGetWindowTitle(sp_all_child_windows[num]) == "&Set Default" then --Win 10 button caption
		if bit32.band(spGetWinStyle(sp_all_child_windows[num]), 0x08000000) == 0x08000000 then
			acMessageBox("Button is disabled")
		else
			acMessageBox("Button is enabled")
		end
	end
end
Also, you still need to define this in your Global Lua tab, in order to get the window styles, called from the above script:
--This function gets the styles for the window, so you can test if it's disabled, for example
function spGetWinStyle(hwnd, x, y)
	if hwnd == nil then hwnd = acGetOwnerWindowByPoint(x, y) end
	local user32 = alien.core.load("user32.dll")
	local GetWindowLong = user32.GetWindowLongA
	GetWindowLong:types{ ret = 'uint', abi = 'stdcall', 'ulong', 'long'}
	return GetWindowLong(hwnd, GWL_STYLE)
end

Note that I'm running Windows 10, so some of this may have to be tweaked for a different version of windows. Obviously, I only wrote the code to determine whether or not the button is enabled, you'll have to take it from here and extend the logic as needed.
Go to Top of Page

Samsiline

Germany
3 Posts

Posted - 02/20/2016 :  08:43:27  Show Profile  Reply with Quote
Thanks a lot!!!
Go to Top of Page

Samsiline

Germany
3 Posts

Posted - 02/27/2016 :  00:31:08  Show Profile  Reply with Quote
Hello Rob,

first, once again, thank you very much for your help! :-)

I tested your code (and extended as needed) but even if Iīm testing your original code, unfortunately the GetWindowLong function returns weired values. Sometimes itīs correct, and the button is actually in the enabled or disabled state, but sometimes the function returns the wrong value. I get no idea, in which cases the correct and in which cases the wrong value is returned (I tried to find a system behind by showing the returned value in message box etc).

Now I tested your code with the ok button (should be always enabled). First call works correct, second call wrong, third call correct, fourth call wrong and so on. I always closed my sound window after each call.

acRunProgram("c:\\windows\\system32\\rundll32.exe","shell32.dll,Control_RunDLL mmsys.cpl,,0",0, 1)
acDelay(1000) --Wait for window to load
sndhwnd = acFindWindow(nil,"Sound") --Works for me on Windows 10
acActivateWindow(sndhwnd)
acGetChildWindows(sndhwnd)
for num, handle in pairs(sp_all_child_windows) do
if acGetWindowTitle(sp_all_child_windows[num]) == "OK" then --Win 10 button caption
if bit32.band(spGetWinStyle(sp_all_child_windows[num]), 0x08000000) == 0x08000000 then
acMessageBox("Button is disabled")
else
acMessageBox("Button is enabled")

break;
end
end
end



Iīm running on Windows 10 64-bit, so I tested GetWindowLongPtr instead of GetWindowsLongA, but I get an error "procedure not found". By using GetWindowsLongW itīs the same issue as by using GetWindowsLongA.


Do you have any idea how to solve this problem?
Go to Top of Page

Rob

USA
2573 Posts

Posted - 02/29/2016 :  10:18:30  Show Profile  Visit Rob's Homepage  Reply with Quote
Hmm, I've copied your script exactly and it always find the OK button is enabled. I'm also running Win 10 64bit, so I'm not sure exactly what is going on. You could try throwing a message box with the button handle: acMessageBox(sp_all_child_windows[num])
and see if it's getting the right handle using an application like Spy++. Just note that S+ is going to show you the handle in integer form, not hex like most apps so you'll need to use Calc to convert dec to hex.
Go to Top of Page

Hard.Wired

62 Posts

Posted - 05/16/2019 :  00:17:36  Show Profile  Reply with Quote
I just noticed that acGetChildWindows(hwnd) never made it into any of the documentation. Glad I ran across this post! I need it!
Go to Top of Page
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
 Printer Friendly
Jump To:
StrokesPlus Forum © 2011-2018 Rob Yapchanyk Go To Top Of Page
Snitz Forums 2000