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

 All Forums
 Lua Scripts
 General Action Scripts
 Identifying tabs in Adobe After Effects
 New Topic  Reply to Topic
 Printer Friendly
Author Previous Topic Topic Next Topic  

breakcore

Russia
74 Posts

Posted - 10/28/2012 :  06:22:44  Show Profile  Reply with Quote
Hi Rob.
I wanted to add to the app list some "child apps" sepatating them by control info, but some controls can only be distinguished by instance number. It would be really great (I think not only for me) if you add a "control instance" qualifier.
Thanks!

Rob

USA
2516 Posts

Posted - 10/28/2012 :  14:52:25  Show Profile  Visit Rob's Homepage  Reply with Quote
Can you provide any additional details? I want to make sure I'm thinking of the same thing you are. Because what I'm thinking of for "control instance" is the handle to the control (Instance Handle in Spy++), which will change every time the control is created and not be very useful in an app definition as you would have to change it constantly.
Go to Top of Page

breakcore

Russia
74 Posts

Posted - 10/28/2012 :  16:27:18  Show Profile  Reply with Quote
Sorry for being laconic, I thought this term is common among programmers=)
afaik, control instance has a permanent value.
i think this animations will explane the idea better then any words:





Edited by - breakcore on 10/28/2012 18:08:20
Go to Top of Page

breakcore

Russia
74 Posts

Posted - 10/28/2012 :  16:34:13  Show Profile  Reply with Quote
So if S+ could able to distinguish the instance I could have individual gesture set for any panel. The same type of controls are existing in adobe premiere pro and adobe audition (i will assume, in all adobe products)
Again sorry for my english...
Go to Top of Page

Rob

USA
2516 Posts

Posted - 10/28/2012 :  17:50:37  Show Profile  Visit Rob's Homepage  Reply with Quote
Ah, the problem is that "Instance" in AutoIt is something they've come up with on their own (google ClassnameNN and it becomes evident).

What they're doing is enumerating all windows in the containing window and when there's another instance of the same class name, it's adding a number to the end and incrementing. So it's not something that can be determined from a standard WinAPI call (and hence my confusion).

I'll have to think about this some, as I don't want to add the overhead to every stroke button down to enumerate every window owned by an application; for a hotkey-based setup like AHK, this is fine, but adding that to every single right-mouse down introduces way too much unnecessary processing.

However, I've downloaded After Effects and will see what I can come up with for you.
Go to Top of Page

breakcore

Russia
74 Posts

Posted - 10/28/2012 :  18:39:23  Show Profile  Reply with Quote
quote:
Ah, the problem is that "Instance" in AutoIt is something they've come up with on their own

didn't knew that
quote:
What they're doing is enumerating all windows in the containing window and when there's another instance of the same class name, it's adding a number to the end and incrementing.

That is right, I had checked - when i close one of the panels, the next panel takes it's instance number, so the value isn't permanent as I thought...
quote:
However, I've downloaded After Effects and will see what I can come up with for you.

I really appreciate your willingness to help!
Go to Top of Page

Rob

USA
2516 Posts

Posted - 10/28/2012 :  20:57:15  Show Profile  Visit Rob's Homepage  Reply with Quote
So far, the only thing I can think of would require you to initialize the tabs, which is a pain but may be worth it if it saves you time.

It starts in the Global Lua tab; this assumes you haven't already initialized the alien variable, so adjust as needed if so:
aliencore = alien.core
user32 = aliencore.load("user32.dll")
-- ************ GetParent ************

gGetParent = user32.GetParent
gGetParent:types{ ret = 'long', abi = 'stdcall', 'long'}

function aGetParent(iWnd)
	return gGetParent(iWnd)
end

-- ************ IsWindow ************

gIsWindow = user32.IsWindow
gIsWindow:types{ ret = 'long', abi = 'stdcall', 'long'}

function aIsWindow(iWnd)
	return gIsWindow(iWnd)
end

Create your application definition; I just selected File Name: AfterFX.exe


Create an action which will initialize a tab's handle. For example, I made an action using the gesture C to initialize the Composition tab:
local hTemp = acGetWindowByPoint(gsx, gsy)
local sTemp = acGetWindowTitle(hTemp, nil, nil)
if sTemp == "DroverLord - TabPanel Window" then
	--acMessageBox("Found Tab Window","",nil)
	hAECompositionWindow = hTemp
else
	hTemp = aGetParent(hTemp)
	sTemp = acGetWindowTitle(hTemp, nil, nil)
	if sTemp == "DroverLord - TabPanel Window" then
		--acMessageBox("Found Tab Window","",nil)
		hAECompositionWindow = hTemp
	else
		acMessageBox("Couldn't find DroverLord - TabPanel Window","",nil)
		hAECompositionWindow = nil
	end
end

So what I do is draw the C gesture inside the Composition tab and the script finds the Tab control class (sometimes it's nested one deep, which is why I check the control, then the parent). After the script assigns the control handle to hAECompositionWindow, the other actions are ready to work within that tab. Note that hAECompositionWindow does not have "local" in front of it, this allows the variable to exist outside of that action.

So then I created this action, which is the one that would actually do the action you're looking for; I set it up to work with the Right-Down gesture:
if aIsWindow(hAECompositionWindow) == 1 then
	acMessageBox("Do something here","",nil)
else
	acMessageBox("hAECompositionWindow not a window","",nil)
end

Is checks to see if hAECompositionWindow refers to an actual window (control), if so it shows you the message box (which you would replace with your desired code).

As I mentioned, it seems like a lot of work, but really it's just a quick one-time init (per tab) when you open AE and everything will be fine thereafter. Note that you would need to create separate initialization actions for each tab you want to have actions work within. You would open AE, then draw the gestures over each tab to store the handles (using different variables like hAECompositionWindow). Of course, if you want to have the same action definition work in multiple tabs but do different things (e.g. the Up gesture does different things in different tabs), you'd have to have multiple if then checks in a single action. For example, it would check the window under the mouse (and maybe its parent) and if it == hAECompositionWindow, do something, if it equals hAEProjectWindow (something you would init separately), it does something different.

I hope this makes sense; I wish there were a better way of doing it which would fit into the S+ design, but as you noticed, I don't think working with non-permanent identifiers is something I want to have to support (explaining over and over to others why S+ isn't broken, but the count has simply changed) nor have affect the performance of S+.

Another alternative would work only if you always kept the tabs in exactly the same position. It would involve checking the mouse coordinates to identify the tabs. So if the mouse X is between 400 and 650 and mouse Y is between 300 and 500, then that is the Composition window area and do something for that area..or if it's X between 100 and 200 and Y between 300 and 500 it's the Project tab, etc. But that's probably more work and less flexible than my above solution.

Important note: Since S+ version 2.1.8 there are two instances of the Lua engine. This is to handle multiple gestures being fired in rapid succession without trying to run in the same Lua instance (to prevent crashes). Each of these states are initialized and function the same, but are separate. So if you initialized hAECompositionWindow in Lua instance 1 (the default instance, always the one that's used unless it's busy running another action), then you fired actions in the Composition tab extremely fast, you could possibly cause the subsequent action to be executed in Lua instance 2, where hAECompositionWindow was never initialized. For the most part, this shouldn't happen; you have to either be very quick or have a long running action which is still processing while you've fired another (which wouldn't make sense for this usage in an AE tab). Just wanted to mention for completeness.

Rob
Go to Top of Page

breakcore

Russia
74 Posts

Posted - 10/29/2012 :  04:50:06  Show Profile  Reply with Quote
WOW! Rob, thank you so much for your effort!
I think I'll be using the first solution, since I relocate the tabs often.

Edited by - breakcore on 10/29/2012 05:03:58
Go to Top of Page

Rob

USA
2516 Posts

Posted - 10/29/2012 :  05:53:29  Show Profile  Visit Rob's Homepage  Reply with Quote
You're welcome! Don't hesitate to post any follow up questions about setting up these scripts. I figured I'd wait to see if you even wanted to bother with this before expanding on the details further.
Go to Top of Page

Rob

USA
2516 Posts

Posted - 10/29/2012 :  07:00:05  Show Profile  Visit Rob's Homepage  Reply with Quote
I took it a little further by adding another action to initialize the Project tab (used gesture P):
local hTemp = acGetWindowByPoint(gsx, gsy)
local sTemp = acGetWindowTitle(hTemp, nil, nil)
if sTemp == "DroverLord - TabPanel Window" then
	hAEProjectWindow = hTemp
else
	hTemp = aGetParent(hTemp)
	sTemp = acGetWindowTitle(hTemp, nil, nil)
	if sTemp == "DroverLord - TabPanel Window" then
		hAEProjectWindow = hTemp
	else
		acMessageBox("Couldn't find DroverLord - TabPanel Window","",nil)
		hAEProjectWindow = nil
	end
end

Then changed the action script to something which will recognize the different areas in a single action:
if (acGetWindowByPoint(gsx, gsy) == hAECompositionWindow or aGetParent(acGetWindowByPoint(gsx, gsy)) == hAECompositionWindow) then
	acMessageBox("Composition window","",nil)
elseif (acGetWindowByPoint(gsx, gsy) == hAEProjectWindow or aGetParent(acGetWindowByPoint(gsx, gsy)) == hAEProjectWindow) then
	acMessageBox("Project window","",nil)
else
	acMessageBox("Other window","",nil)
end

So now I open AE, draw a C over the Composition tab and a P over the Project tab and the new action understands which area I've drawn over.

Note that whenever you click Apply, OK, Cancel in the S+ settings window, both Lua states are re-initialized so you'll have to re-initialize the AE tabs (as you've probably noticed).
Go to Top of Page

Rob

USA
2516 Posts

Posted - 10/29/2012 :  07:35:21  Show Profile  Visit Rob's Homepage  Reply with Quote
*sigh*

Ok, my obsessive nature has led to further refinements . The new scripts are smarter and more reuseable for other actions. Including all code in this post so it's easier to follow for others in the future. Note that I've created two new functions in Global Lua to make finding parent windows easier and more robust.

In Global Lua tab
aliencore = alien.core
user32 = aliencore.load("user32.dll")

-- ************ GetParent ************

gGetParent = user32.GetParent
gGetParent:types{ ret = 'long', abi = 'stdcall', 'long'}

function aGetParent(iWnd)
	return gGetParent(iWnd)
end

-- ************ IsWindow ************

gIsWindow = user32.IsWindow
gIsWindow:types{ ret = 'long', abi = 'stdcall', 'long'}

function aIsWindow(iWnd)
	return gIsWindow(iWnd)
end

-- ******** aFindParentByWindowTitle ********
-- Starting with a window handle, this function traverses parent windows
-- until a window with the supplied title is found; if no match, returns nil

function aFindParentByWindowTitle(hwnd, title)
	if hwnd == nil or hwnd == 0 or title == nil or title == "" then
		return nil
	end 
	local hTemp = aGetParent(hwnd)
	if hTemp ~= nil then
		if acGetWindowTitle(hwnd, nil, nil) == title then
			return hTemp
		else	
			return aFindParentByWindowTitle(hTemp, title)
		end
	else
		return nil
	end
end


-- ******** aFindParentByWindow ********
-- Starting with a window handle, this function traverses parent windows
-- until a window with the supplied handle (hwndparent) is found; if no match, returns nil

function aFindParentByWindow(hwnd, hwndparent)
	if hwnd == nil or hwnd == 0 or hwndparent == nil or hwndparent == 0 then
		return nil
	end 
	local hTemp = aGetParent(hwnd)
	if hTemp ~= nil then
		if hTemp == hwndparent then
			return hTemp
		else	
			return aFindParentByWindow(hTemp, hwndparent)
		end
	else
		return nil
	end
end

Action: Initialize Composition tab (window)
hAECompositionWindow = aFindParentByWindowTitle(acGetWindowByPoint(gsx, gsy), "DroverLord - TabPanel Window")
if hAECompositionWindow == nil then
	acMessageBox("Couldn't find DroverLord - TabPanel Window","",nil)
end

Action: Initialize Project tab (window)
hAEProjectWindow = aFindParentByWindowTitle(acGetWindowByPoint(gsx, gsy), "DroverLord - TabPanel Window")
if hAEProjectWindow == nil then
	acMessageBox("Couldn't find DroverLord - TabPanel Window","",nil)
end

Action: Will work in either tab, after the tabs are initialized using the above actions
if aFindParentByWindow(acGetWindowByPoint(gsx, gsy), hAECompositionWindow) ~= nil then
	acMessageBox("Composition window","",nil)
elseif aFindParentByWindow(acGetWindowByPoint(gsx, gsy), hAEProjectWindow) ~= nil then
	acMessageBox("Project window","",nil)
else
	acMessageBox("Other window","",nil)
end
Go to Top of Page

breakcore

Russia
74 Posts

Posted - 10/29/2012 :  10:05:34  Show Profile  Reply with Quote
OMG
I've not yet fully digged into your updates, since I myself was enthusiastic with what i've come up with on my own
My approach seems a little easier. i'm not sure about stability yet, but it do the job:
i've made a "right-down" gesture with the script that updates all tab handle values in a global lua script file, so they are staying permanent during whole session:



the init gesture script: {stroke_button>>right-down}
--get handles of the tabs
tab1=acGetWindowByPoint(gsx, gsy)
tab2=acGetWindowByPoint(gbr, gsy)
tab3=acGetWindowByPoint(gex, gey)
--open the global script for reading 
local file_r=io.open("G:\\Program Files\\StrokesPlus_x86\\StrokesPlus.lua", "r")
file_s=file_r:read("*a")
file_r:close()
--change the handle values
file_s=string.gsub(file_s,"aecs3_1h=(%d+)","aecs3_1h="..tab1)
file_s=string.gsub(file_s,"aecs3_2h=(%d+)","aecs3_2h="..tab2)
file_s=string.gsub(file_s,"aecs3_3h=(%d+)","aecs3_3h="..tab3)
--update the global script file
local file_w=io.open("G:\\Program Files\\StrokesPlus_x86\\StrokesPlus.lua", "w")
file_w:write(file_s)
file_w:close()
a part from global lua script:
aecs3_1h=3410182	--project tab handle
aecs3_2h=1705678	--composition tab handle
aecs3_3h=723270		--timeline tab handle


simple gesture example: {stroke_button+Wheel up}
WM_MOUSEWHEEL = 0x20A
WHEEL_NEG = 0xff880000
WHEEL_POS = 0x00780000
hndl=acGetWindowByPoint(gsx, gsy)   --get handle
if hndl==aecs3_2h then	--if the cursor on the composition panel then zoom-in to mouse position (not to the center)
    acSendAltDown()
    acSendKeys({Delay 100})
    acPostMessage(hndl, WM_MOUSEWHEEL, WHEEL_NEG, bit32.lshift(gsy,16)+gsx)
    acSendAltUp()
    acSendKeys({Delay 100})
elseif hndl==aecs3_3h then acSendKeys("{PLUS}") --if the cursor on the timeline panel then zoom-in the timeline
end

Edited by - breakcore on 10/29/2012 16:22:58
Go to Top of Page

Rob

USA
2516 Posts

Posted - 10/29/2012 :  10:08:25  Show Profile  Visit Rob's Homepage  Reply with Quote
Oh yea, that's a great solution too!

I love to see what other people come up with
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