Author |
Topic |
|
Samsiline
Germany
3 Posts |
Posted - 02/18/2016 : 01:00:10
|
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
2615 Posts |
Posted - 02/19/2016 : 22:35:22
|
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. |
|
|
Rob
USA
2615 Posts |
Posted - 02/19/2016 : 23:22:13
|
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. |
|
|
Samsiline
Germany
3 Posts |
Posted - 02/20/2016 : 08:43:27
|
Thanks a lot!!! |
|
|
Samsiline
Germany
3 Posts |
Posted - 02/27/2016 : 00:31:08
|
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?
|
|
|
Rob
USA
2615 Posts |
Posted - 02/29/2016 : 10:18:30
|
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. |
|
|
Hard.Wired
84 Posts |
Posted - 05/16/2019 : 00:17:36
|
I just noticed that acGetChildWindows(hwnd) never made it into any of the documentation. Glad I ran across this post! I need it! |
|
|
|
Topic |
|
|
|