This App is No Longer Maintained. Visit the Replacement at StrokesPlus.net

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

 All Forums
 Lua Scripts
 General Action Scripts
 Cycle Through Programs [including Win8 apps]
 Forum Locked
 Printer Friendly
Author Previous Topic Topic Next Topic  

kwaka

Ukraine
9 Posts

Posted - 02/10/2013 :  16:52:46  Show Profile
Hello Rob!
I tried the command from the topic "Creating a gesture to cycle thru win" with the CTRL+WIN+Tab, it works fine, but how to make the scrolling window in the backwards direction like a WIN+Shift+Tab?
Also, as to conclude the selected window to the front after the stroke button is released, like a win-key is released in the manually WIN+Tab?
P.S. The command like a acPreviousApplication() did not work for me, because it toggles between the only two last windows, i do it with the Alt+Tab.

Edited by - kwaka on 02/10/2013 18:05:47

Rob

USA
2615 Posts

Posted - 02/10/2013 :  18:10:03  Show Profile  Visit Rob's Homepage
I'm running Windows 8 now and those keystrokes don't do anything, so it's hard for me to test (my Win 7 VM doesn't run with Aero on either, so I can't pull up the Aero flip).

Have you tried acSendKeys("^%{TAB}")? I think this pulls up the task switcher, which you can scroll through with the mouse wheel.

Have you tried acNextApplication() with a mouse wheel scroll modifier? It's not like acPreviousApplication, which is exactly like ALT+TAB; acNextApplication() goes through all top-level windows.

Some of the reasons why having S+ invoke the task switcher and emulate pressing the tab key are listed in this thread. Essentially, you can't truly simulate pressing and holding some Windows key sequences because Windows takes over.
Go to Top of Page

kwaka

Ukraine
9 Posts

Posted - 02/11/2013 :  05:05:53  Show Profile
Yes, i tried this commands and other combitations of Ctrl-Alt-Win-Shift-Tab:
acSendKeys("^@{TAB}") - one way direction of switching and needs to additionally hit Enter-key or left mouse click to foreground selected window.
acSendKeys("^%{TAB}") - same problems as above.
acSendKeys("^+%{TAB}") - It needs to additionally hit Enter-key or left mouse click to foreground selected window.
acNextApplication() - one way direction of switching.

So, no one of these commands no satisfy the task - two way direction of switching windows with conclude the selected window to the front.
It is possible to write some script, which emulates Enter-key after the stroke button is released?

Edited by - kwaka on 02/11/2013 05:15:11
Go to Top of Page

Rob

USA
2615 Posts

Posted - 02/11/2013 :  09:44:05  Show Profile  Visit Rob's Homepage
Ok, I've added a new option in 2.6.2 named Allow After Release script* which will let you define a function in Global Lua named sp_after_release. That function will be called after the stroke button is released, as long as S+ captured the stroke button (meaning, you didn't just single right-click somewhere). To be flexible, this function will always fire regardless of a match. If you need to control it, you could always define a variable in Global Lua which is checked in sp_after_release to see if you want to execute the code contained within.

Or, for example, you may wish to define a global variable to signal the after release script is to be executed and only set it to true in your task switching action (you could also check the gnm variable in sp_before_action; if it's the name of the action, have it set the flag to on).

Below is some code that I put together which seems to do what you're looking for (make sure to check Allow After Release Script* in Preferences first):

[code removed, see updated code below]

Of course, you may want to swap the Up and Down scroll scripts however you'd prefer.

Basically, the script gets all top-level windows, then turns on the bTaskMode value so each wheel scroll doesn't get all the windows again, just works with the state at the time of the first action fire. When you scroll the mouse wheel up or down, each action moves the current position up or down and activates the window at that position; looping back to the top or bottom of the window stack when either end is reached.

When you release the stroke button, sp_after_release is fired which resets the variables so the window list is refreshed the next time you execute either action.

I did notice that minimized windows are activated, but not restored when you reach their position in the stack. There is a way to check for this and handle appropriately, but I don't have a lot of time at the moment to put that together, I will try to provide that later today or tomorrow. Ultimately, you'd need to call (via Alien) the IsIconic Windows API and if the return value is not zero, call acRestoreWindow.

Updated code above with the necessary script to restore windows that are minimize while cycling through.

I'm sure there is room for improvement in these scripts and the overall flow, but it's something I quickly hacked together. However, it should give you enough to start with.
Go to Top of Page

Rob

USA
2615 Posts

Posted - 02/11/2013 :  13:49:11  Show Profile  Visit Rob's Homepage
Code updated to handle minimized windows.
Go to Top of Page

Rob

USA
2615 Posts

Posted - 02/11/2013 :  14:50:51  Show Profile  Visit Rob's Homepage
Ha, for some reason, the key combos weren't working for me on Win8 yesterday (CTRL+WIN+TAB, etc). Now they're working fine.
Go to Top of Page

Rob

USA
2615 Posts

Posted - 02/11/2013 :  14:59:24  Show Profile  Visit Rob's Homepage
Ok, so given that these hotkeys are now working for me, here's the scripts to use WIN+TAB / WIN+SHIFT+TAB:


Global Lua
bTaskMode = 0

function sp_after_release()
	if bTaskMode == 1 then
		acSendWinUp()
	end
	bTaskMode = 0
end


Scroll Up Action
if bTaskMode == 0 then
	acSendWinDown()
	bTaskMode = 1
end
acSendKeys("+{TAB}")


Scroll Down Action
if bTaskMode == 0 then
	acSendWinDown()
	bTaskMode = 1
end
acSendWinDown()
acSendKeys("{TAB}")
Go to Top of Page

Rob

USA
2615 Posts

Posted - 02/11/2013 :  15:01:58  Show Profile  Visit Rob's Homepage
It should be noted that the main difference in the latter script is that it uses the standard Windows functionality for switching apps, not using the method S+ does to determine top-level windows.

The script prior to the last only switches through Desktop (non-Metro) apps that S+ deems are top-level windows, where the latter script isn't limited in that way.
Go to Top of Page

kwaka

Ukraine
9 Posts

Posted - 02/11/2013 :  16:06:35  Show Profile
Rob, thank you for the help and participation!
I see progress.
It almost works... but way with switching tasks is not always working, and does not switch the tasks that runs after the first use of the script.
Way with the WIN+TAB/WIN+SHIFT+TAB does not conclude the selected window to the front and leaves holding Win-key after the first use of the script.
I have Windows7 (x64) and S+ 2.6.1 x64 Signed.

Upd: I update S+ to 2.6.2 x64 Signed, still have same problems.

Edited by - kwaka on 02/11/2013 16:44:51
Go to Top of Page

Rob

USA
2615 Posts

Posted - 02/11/2013 :  16:54:36  Show Profile  Visit Rob's Homepage
Do you have Allow After Release Script* checked in the Preferences tab?
Go to Top of Page

kwaka

Ukraine
9 Posts

Posted - 02/11/2013 :  17:03:22  Show Profile
Yes, of course.
I have checked items:
Aggressively Manage Memory
Reset Cancel Delay On Movement/Modifier
Keep Gesture Draw Window On Top
Don't Hide Gesture Draw Window
Fire Recognition on Mouse Wheel Scroll
Capture Modifiers on Stroke Button Down
Allow After Action Script
Check Cursor Flags
Go to Top of Page

Rob

USA
2615 Posts

Posted - 02/11/2013 :  17:04:22  Show Profile  Visit Rob's Homepage
Allow After Release Script

=)

It was added in 2.6.2.
Go to Top of Page

kwaka

Ukraine
9 Posts

Posted - 02/11/2013 :  17:07:11  Show Profile
Oh, really...
Turned and now will test.
Go to Top of Page

Rob

USA
2615 Posts

Posted - 02/11/2013 :  17:19:54  Show Profile  Visit Rob's Homepage
Just FYI, the difference being Allow After Action Script allows sp_after_action to be called, where Allow After Release Script causes sp_after_release to be called.

The After Action script would fire each time the mouse wheel scrolls, which doesn't work for your situation as it doesn't allow the state of the action (and its pair action) to be known. After Release only fires when the stroke button is released, so we know that the action(s) are no longer being used; to clear the variables so the next will get the current window list or send the WIN up event to conclude the action.
Go to Top of Page

kwaka

Ukraine
9 Posts

Posted - 02/11/2013 :  17:25:26  Show Profile
Rob! It works!!!
Thank you for your work and intelligence.
The script with task switching, too, everything works, but sometimes confused the order of task switching. But it is not so important because the Win+Tab script works perfectly!
It seems to me, Win+Tab script can be added to the library or the presetting together with the control volume script, it would be useful to many users.
Go to Top of Page

Rob

USA
2615 Posts

Posted - 02/11/2013 :  17:27:03  Show Profile  Visit Rob's Homepage
Glad to hear it's working!
Go to Top of Page

Rob

USA
2615 Posts

Posted - 02/13/2013 :  12:40:53  Show Profile  Visit Rob's Homepage
Updated the code for 2.6.3 which allows you to also cycle through Windows 8 apps. Note that the code below skips the Windows 8 Start screen (ImmersiveLauncher), you can remove that check if you want the Start screen to appear as you scroll through windows.

Yes, this functionality could certainly be refactored to be less redundant, but I'm rushed at the moment and don't feel like doing it right now!

Important: Make sure to check Allow After Release Script* in Preferences for this to work properly:


Global Lua:
bTaskMode = 0
iTaskCount = 0
iTaskPosition = 0

function sp_after_release()
	bTaskMode = 0
	iTaskCount = 0
	iTaskPosition = 0	
end

aliencore = alien.core
user32 = aliencore.load("user32.dll")

-- ************ IsIconic ************

gIsIconic = user32.IsIconic
gIsIconic:types{ ret = 'long', abi = 'stdcall', 'long'}
function aIsIconic(iWnd)
	return gIsIconic(iWnd)
end



Scroll Up Action:
if bTaskMode == 0 then
	bTaskMode = 1
	acGetAllWindows(1)
	for num, handle in pairs(sp_all_windows) do 
		iTaskCount = iTaskCount + 1
	end
end
local iStartingPosition = iTaskPosition
::top::
iTaskPosition = iTaskPosition - 1
if iTaskPosition < 0 then
	iTaskPosition = iTaskCount-1
end

--get the window class to test for excluded windows
local sClass = acGetClassName(sp_all_windows[iTaskPosition],0,0) 

--exclude these windows
if sClass ~= "SearchPane" and sClass ~= "Shell_CharmWindow" 
and sClass ~= "ImmersiveLauncher" and sClass ~= "Snapped Desktop" 
and sClass ~= "ImmersiveBackgroundWindow" and sClass ~= "NativeHWNDHost" 
and sClass ~= "MetroGhostWindow" then
	--if the window is minimized, restore it
	if aIsIconic(sp_all_windows[iTaskPosition]) ~= 0 then
		acRestoreWindow(sp_all_windows[iTaskPosition])
	end
	--activate the window
	acActivateWindow(sp_all_windows[iTaskPosition])
else
	--the line below ensures the script won't get stuck in a recursive loop
	--if there are only excluded windows present
	if iTaskPosition ~= iStartingPosition then
		goto top
	end
end



Scroll Down Action:
if bTaskMode == 0 then
	bTaskMode = 1
	acGetAllWindows(1)
	for num, handle in pairs(sp_all_windows) do 
		iTaskCount = iTaskCount + 1
	end
end
local iStartingPosition = iTaskPosition
::top::
iTaskPosition = iTaskPosition + 1
if iTaskPosition >= iTaskCount then
	iTaskPosition = 0
end

--get the window class to test for excluded windows
local sClass = acGetClassName(sp_all_windows[iTaskPosition],0,0) 

--exclude these windows
if sClass ~= "SearchPane" and sClass ~= "Shell_CharmWindow" 
and sClass ~= "ImmersiveLauncher" and sClass ~= "Snapped Desktop" 
and sClass ~= "ImmersiveBackgroundWindow" and sClass ~= "NativeHWNDHost" 
and sClass ~= "MetroGhostWindow" then
	--if the window is minimized, restore it
	if aIsIconic(sp_all_windows[iTaskPosition]) ~= 0 then
		acRestoreWindow(sp_all_windows[iTaskPosition])
	end
	--activate the window
	acActivateWindow(sp_all_windows[iTaskPosition])
else
	--the line below ensures the script won't get stuck in a recursive loop
	--if there are only excluded windows present
	if iTaskPosition ~= iStartingPosition then
		goto top
	end
end
Go to Top of Page

Hard.Wired

84 Posts

Posted - 04/17/2019 :  22:10:02  Show Profile
I'm having some difficulty filtering out Windows 10 store apps (i.e. UWP, Immersive, etc.) that are only running in the background as a result of "Settings / Privacy / Background apps" being On or Start Menu Live Tiles. I've used all the sClass names from Rob's posts above, but these Windows 10 apps seem to be class designated as "ApplicationFrameWindow" whether they are activated by the user or not. Can anyone point me in the right direction?
Go to Top of Page

Rob

USA
2615 Posts

Posted - 04/18/2019 :  05:26:44  Show Profile  Visit Rob's Homepage
Unfortunately, those windows don't follow the standard rules of visibility after Win8. There's a separate method to detect cloaked windows which must be called, see this thread for details:

https://stackoverflow.com/questions/32149880/how-to-identify-windows-10-background-store-processes-that-have-non-displayed-wi

I'm updating the StrokesPlus.net SystemWindow class to include a .IsCloaked property in the next release (0.2.9.8), but I can't even build StrokesPlus right now due to many missing headers/libraries/SDK. I'm getting a new laptop in the next week or so and will try to get S+ buildable again.
Go to Top of Page

Rob

USA
2615 Posts

Posted - 04/18/2019 :  06:35:05  Show Profile  Visit Rob's Homepage
You might be able to get this to work via alien, I'm just not familiar enough to understand passing and dereferencing pointers via alien. This is what I have so far in the Global Lua tab:
Dwmapi = aliencore.load("Dwmapi.dll")

gDwmGetWindowAttribute = Dwmapi.DwmGetWindowAttribute
gDwmGetWindowAttribute:types{ ret = 'int', abi = 'stdcall', 'long', 'long', 'pointer', 'int' }

function aIsCloaked(hwnd)
	--local cloakedval
	cloakedval = aliencore.buffer(4)
	cloakedval:set(0, 0)
	local ret = gDwmGetWindowAttribute(hwnd, 14, cloakedval, 4)
	acMessageBox(cloakedval:get(0, "int"), "ret")
	return cloakedval
end

In the action:
local hWnd = acGetForegroundWindow()
acMessageBox(hWnd, "Foreground IsCloaked")
acMessageBox(aIsCloaked(469178), "Calendar IsCloaked") --Got handle from Spy++
acMessageBox(aIsCloaked(21706810), "Calculator IsCloaked") --Got handle from Spy++
This is not complete code, I just can't spend any more time right now on it, so I figured I'd see if you could figure it out.

Function docs: https://docs.microsoft.com/en-us/windows/desktop/api/dwmapi/nf-dwmapi-dwmgetwindowattribute (the 14 in my script is the DWMWA_CLOAKED in the DWMWINDOWATTRIBUTE enum)

I'm getting back "512" for Calc and Calendar, but that doesn't seem right based on the values DWMWA_CLOAKED should return (1/2/4 bitwise).
Go to Top of Page

Hard.Wired

84 Posts

Posted - 04/18/2019 :  23:50:46  Show Profile
OMG! Thank you Rob! "Cloaked"!!!

This also seems to hint at why the Windows 10 task bar menu commands "Stack windows ..." commands are broken when these phantom (cloaked) windows are active!!! Or does it? Seems like Microsoft would have fixed it by now.

I'm off to do a deep dive on these code examples. So much to learn here.
Go to Top of Page

Rob

USA
2615 Posts

Posted - 04/19/2019 :  04:14:23  Show Profile  Visit Rob's Homepage
I changed the buffer size and offset to 1 (though still passing size of 4 to the API call as expects an int behind the scenes), since it's really just a single byte of storage needed. This does seem to be responding fine, returns 1 if cloaked, 0 if not. But I've only tested against the specific cases here, not a real world full test

It's possible I've just made it coincidentally return the right values for these windows...so it needs more testing and/or better understanding of the pointer processing in alien.

--Global Lua
Dwmapi = aliencore.load("Dwmapi.dll")
gDwmGetWindowAttribute = Dwmapi.DwmGetWindowAttribute
gDwmGetWindowAttribute:types{ ret = 'int', abi = 'stdcall', 'long', 'long', 'pointer', 'int' }

function aIsCloaked(hwnd)
	--local cloakedval
	cloakedval = aliencore.buffer(1)
	cloakedval:set(0, 0)
	local ret = gDwmGetWindowAttribute(hwnd, 14, cloakedval, 4)
	--acMessageBox(cloakedval:get(1, "int"), "ret")
	--ret == 0 check ensures the API call itself returned 0 (success)
	--then check to see if the buffer value is greater than zero
	if ret == 0 and cloakedval:get(1, "int") > 0 then
		return 1
	else
		return 0
	end
end

--Action
acMessageBox(aIsCloaked(hWnd), "Foreground IsCloaked")
acMessageBox(aIsCloaked(469178), "Calendar IsCloaked") --Got handle from Spy++
acMessageBox(aIsCloaked(21706810), "Calculator IsCloaked") --Got handle from Spy++
Go to Top of Page

Hard.Wired

84 Posts

Posted - 04/20/2019 :  03:03:56  Show Profile
Very nice! The last bit of code seems to be working.

Thanks again!

Edited by - Hard.Wired on 04/20/2019 14:18:47
Go to Top of Page

Hard.Wired

84 Posts

Posted - 05/10/2019 :  07:03:25  Show Profile
I've noticed that when these background windows are first started, there is a slight delay before they get the Cloaked flag. Very... annoying.
Go to Top of Page
  Previous Topic Topic Next Topic  
 Forum Locked
 Printer Friendly
Jump To:
StrokesPlus Forum © 2011-2018 Rob Yapchanyk Go To Top Of Page
Snitz Forums 2000