[UCR Plugins] Zoom.ahk +more

Post gaming related scripts
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

[UCR Plugins] Zoom.ahk +more

12 Nov 2016, 17:20

Edit: 2019-08-27
Updated the Zoom plugin.
This thread houses the following custom user plugins for UCR, descriptions are available a few posts down, see, Note that some of these plugins can be linked to eachother via the link tab, that is, they can trigger in chain. This is a very experimental feature, but could be useful.

Other user plugins:
Zoom - Update - Version 2.1.1 (2017-04-10)
Update - Version 2.1.2 (2018-12-10): Bug fix.
Update - Version 2.1.1 (2017-04-10): Fixed bug fix bug :wtf:
Update - Version 2.1 (2017-04-09): Bug fix, Added new feature: Show cursor on zoom window, mapped from source rectangle.
Mini update (2017-01-04): Added CodeThread to linkTypes array.
Update - Version 2. (2016-12-05)
This has been, quite extensively, updated. Most importantly, I have fixed a bug so you can now have multiple instances of the plugin without weird results. The previous description still holds, these are the new features, in summary:

Features for convenience
  • Click and drag to select custom zoom box coordinates.
  • Click and point to select custom pop-up location.
  • Linking of multiple plugins, such that one hotkey can trigger more than one. (Very experimental, code was made in another context, seems mostly ok)
Features for usage
  • On-the-fly zoom, i.e., click and drag over area of interest, to zoom in (or out) on it. (Highlighted in demo 2)
  • Option to make zoom window click-through-able, this prevents it from capturing the mouse, and hence taking away control from the source (game). Recommended for zooming an FPS, the original purpose of this plugin.
  • Option to hide the source. Caveat: Don't use together with Source->Use active window. (Highlighted in demo 1)
  • Interactive clicks, (left and/or right) mouse clicks on the zoom pop-up are mapped to the source. Two methods, 1) ControlClick, source need not be visible, 2) Click, more reliable but source needs to be visible, no drag possible. (Highlighted in demo 2)
  • Optional hotkey to move the zoom pop-up.
Video preview.
  • Demo 1, shows hiding of source, and interactive clicks, method 1. Zooms out a browser window and interacts with the youtube video player
  • Demo 2, shows on-the-fly zoom, randomly zooming some small images.
Download. (Version 2.1.2)
zoom.ahk
(77.66 KiB) Downloaded 669 times
Additional credits.
  • Mouse effects for Demo 1:
mright wrote: Mouse ripple effect

Original post. (2016-11-12) Edit: removed code, use v2.1.
Introduction.
This is a user plugin for Universal Control Remapper - UCR, v0.1.5, with the purpose to enable zooming in or out on any part of any window.
This was originally a request at this thread. Some features are a consequence of that.

Features.
List of main features:
  • The zoom is live, meaning any change on the source window is imediately seen on the zoom window.
  • Toggle zoom on/off or zoom only while holding the selected hotkey.
  • Choose whether to include non-client area or not.
  • Point and click to select source (Source tab -> Get Source button).
  • Option to specify a custom rectangle on the source window to zoom. By default, the center of the window is zoomed. (See preview 1)
  • Option to specify where on the screen the zoom pop-up window will be placed.
  • Preset pop-up locations to match source corner, could be useful for something like a mini-map zoom. (See preview 2)
  • Option to disable zoom when source is not the active window.
  • By courtesy of the UCR, settings are preserved and very nice hotkey selection functionality.
  • Very low CPU usage.
Animated gif preview.
Preview 1
Preview 2
Installation.
Download UCR, unzip, no installation required, save this plugin to UCR\Plugins\User\zoom.ahk. Start UCR, Select Zoom from the Plugin Selection dropdown list, click Add.

Setup.
You need to select a hotkey to toggle the zoom, and a source window, that is, select the window to zoom. You can choose to zoom the currently active window.
Options should be mostly self-explanatory, if you have questions, please ask.

About the implementation.
The display of the source window on the zoom pop-up window, is handled by the DWM, specifically, a thumbnail relationship between the source window and the pop-up window is registred, then it is just a matter of making some simple coordinate tranformations to get the correct size and placement.
To make something similar, or to make this independent of UCR, you basically just need the dwm_ functions, the rest of the code is mostly settings handling and simple coordinate tranformations. You can follow the links in the comments to learn more, or, feel free to ask.

Known limitations and problems.
  • Requires Windows Vista or newer OS.
  • Probably doesn't work in fullscreen.
  • Hide mouse cursor option doesn't seem to work reliably. I do not know why.
  • You cannot select mouse wheel up or down as hotkeys (for now).
  • When Only zoom client frame-option is used, some source windows, eg ones with a menu, might not be correctly zoomed. This is due to GetClientRect and DWM not agreeing on what is the client-area. As a workaround, specify a custom source rectangle.
  • All combinations of available settings are not really meant to used, but you still can. Result may be awkward.
  • Limited testing.
Cretdits.
  • evilC for making UCR.
  • ShareX for software to record gif, very nice tool, check it out!
  • Gif previews are hosted by giphy.com - I do not know for how long they will be available.
Misc.
A brief comment on the choise of format, although this is not a control remapping, making it as a UCR plugin, is a convenient way to wrap a simple class in a GUI, making it easy to use for non-programmers (most gamers). Also, save me the time to explain how to use this :wave:

Good luck and have fun!
Last edited by Helgef on 27 Aug 2019, 12:20, edited 9 times in total.
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: [UCR Plugin] Zoom - Zoom in or out any window.

13 Nov 2016, 13:47

Awesome, officially the first plugin for UCR that was written from scratch by someone other than myself :)
Thank you so much for the time you put into this Helgef, and the feedback that you have provided.

I have a bit of a nasty bug that I am chasing at the moment, but I hope to try and address the mouse wheel issue soon.
guest3456
Posts: 3453
Joined: 09 Oct 2013, 10:31

Re: [UCR Plugin] Zoom - Zoom in or out any window.

13 Nov 2016, 13:49

Helgef wrote: Animated gif preview.
Preview 1
quake3 ?????

Helgef wrote: Gif previews are hosted by giphy.com - I do not know for how long they will be available.
probably a while:
https://techcrunch.com/2016/02/16/giphy ... valuation/

Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [UCR Plugin] Zoom - Zoom in or out any window.

13 Nov 2016, 14:33

evilC wrote:Awesome, officially the first plugin for UCR that was written from scratch by someone other than myself :)
Cheers! :D
guest3456 wrote: quake3 ?????
Yes :dance: I think its from quakecon 2015, good stuff. Also, I didn't realise until now, it is evil playing, no relation with evilC I supose?
guest3456 wrote: probably a while:
Cool.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [UCR Plugin] Zoom - Zoom in or out any window.

05 Dec 2016, 06:49

This has been updated, see the first post.
When I get time to type a short description, I will share an additional, very simple plugin. It will get its home in this thread aswell.
Suns

Re: [UCR Plugin] Zoom - Zoom in or out any window.

28 Dec 2016, 19:16

Hi, I am getting: Failed to register thumbnail relationship error.

I am on windows 7.

Any idea what is causing this issue?
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [UCR Plugin] Zoom - Zoom in or out any window.

29 Dec 2016, 00:53

It could be due to having Aero theme disabled. If that's not the case I'll need more details and refresh my memory with respect to this code.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [UCR Plugin] Zoom - Zoom in or out any window.

03 Jan 2017, 17:57

WindowStyler
This is simple plugin for moving, resize, hiding and applying a few different styles to a window. Originally it was meant to complement the Zoom plugin with the abillity to hide the source, in v2 of Zoom that was added to the plugin instead.
Some features:
  • Resize (custom or full screen)
  • Move
  • Hide/show
  • Minimise/maximise
  • Activate/send to bottom
  • Set transparency
  • Remove borders and caption
Known limitations:
  • Resize to full screen do not consider multi-monitor setups.
  • Very limited testing.
Download.
Save as WindowStyler.ahk

Code: Select all

class WindowStyler extends _UCR.Classes.Plugin
{
	; Author: Helgef
	; Date: 2016-11-30
	; Version 1.
	; Instructions at: https://autohotkey.com/boards/viewtopic.php?f=19&t=24538
	; Credits to evilC for making UCR (https://github.com/evilC/UCR)
	
	; Plugin variables
	type:="WindowStyler"
	description:="Edit a windows style and dimensions."
	
	static linkTypes:={"Zoom":0, "WindowStyler":0, "CodeThread":0}	; List of plugin types that can be linked to.
	
	init()
	{
		WinShow, % "ahk_id " this.sId
		; Misc
		this.WinTitle:=""				; Source wintitle
		this.ucrHWND:=UCR.hwnd			; UCR hwnd, used in pickGame() 
		this.doNothingFunc:=ObjBindMethod(this,"doNothing")
		
		; Gui
		; Rows for gui placement
		; Most controls are placed at rowX, colY, defined here:
		row1:=" y35 ",  	row1_:=" y32 "
		row2:=" y65 ",  	row2_:=" y62 "
		row3:=" y95 ",  	row3_:=" y92 "
		row4:=" y125 ", 	row4_:=" y123 "
		row5:=" y155 ", 	row5_:=" y153 "
		row6:=" y185 ", 	row6_:=" y183 "
		row7:=" y215 ", 	row7_:=" y213 "
		
		; Columns for gui placement
		col1:=" x15 ", col2:=" x200 ", col3:=" x335 ", col4:=" x455 "
		
		Gui, Add, Tab2, w650 h245, % "Window|Styles|Link|Help"
		; Window tab
		Gui, Tab, 1
		
		; Pick game button.
		; Button to initialise quick source pick routine.
			
		this.AddControl("Edit","exe", 0, row1_ col2  " w125 h25")
		
		Gui, Add, Text, % row2 " x32 ", % "and window title (optional):"
		this.AddControl("Edit","title",0, row2_ col2  " w125 h25")
		
		this.AddControl("Edit","hwndEdit",0, row3_ col2  " w125 h25")
		Gui, Add, Radio, % row1 col1 "hwndsourceRadio1", % "Specify application name (exe):"
		Gui, Add, Radio, % row3 col1 "hwndsourceRadio2", % "Use hwnd"
		Gui, Add, Radio, % row4 col1 "hwndsourceRadio3", % "Use active window (Not recommended)"
		
		this.sourceRadio1:=sourceRadio1
		this.sourceRadio2:=sourceRadio2
		this.sourceRadio3:=sourceRadio3
		this.AddControl("Edit", "SourceRadioEdit", this.checkSourceRadio.Bind(this), "hidden disabled ReadOnly", 1) ; Hidden edit to hold radio choise
		gFunc:=this.SourceRadioChanged.Bind(this)
		GuiControl, +g, % this.sourceRadio1, % gFunc
		GuiControl, +g, % this.sourceRadio2, % gFunc
		GuiControl, +g, % this.sourceRadio3, % gFunc
		
		Gui, Add, Button, % row1_ col3 " w125 hwndpickButton", % "Get source"
		this.pickButton:=pickButton
		gFunc := this.pickGame.Bind(this)
		GuiControl +g, % this.pickButton, % gFunc
		
		Gui, Add, Text, % row5 col1 , % "Hotkey to apply settings:"
		this.AddControl("InputButton","hotkeyApply", 0, this.updateStyle.Bind(this), row5_ col2  " w125 h25")
		
		; Styles tab.
		col4:=" x485 " ; Modify column 4 for this tab
		Gui, Tab, 2
		; Custom window placment and size
		Gui, Add, Text, % row1 col1, % "Position and dimension:"
		this.AddControl("Checkbox", "useCustomWinPlacement", this.winBoxChanged.Bind(this), row2 col1, " Move to specified location")
		Gui, Add, Button, % row2_ col2 "w110 hwndSelectRectButton disabled", % "Select area"
		this.SelectRectButton:=SelectRectButton
		gFunc := this.selectRect.Bind(this)
		GuiControl +g, % this.SelectRectButton, % gFunc
		
		
		Gui, Add, Text, % row3 col1 " hwndCWBText1 disabled", % "Position (x,y):"
		this.CWBText1:=CWBText1
		this.AddControl("Edit", "cwb_x1", 0, row3_ col2 " w50 Number Center Disabled")
		this.AddControl( "Edit", "cwb_y1", 0, row3_ " x+10 w50 Number Center Disabled")
		Gui, Add, Text, % row4 col1 " hwndCWBText2 disabled", % "Size (w,h):"
		this.CWBText2:=CWBText2
		this.AddControl("Edit", "cwb_w", 0, row4_ col2 " w50 Number Center Disabled")
		this.AddControl( "Edit", "cwb_h", 0, row4_ " x+10 w50 Number Center Disabled")
		this.AddControl("Checkbox", "offScreen", this.offScreen.Bind(this), row5 col1, "Move off screen")
		this.AddControl("Checkbox", "fullscreen", this.fullscreen.Bind(this), row6 col1, "Resize to fullscreen")
		
		; Styles
		Gui, Add, Text, % row1 col3, % "Styles:"
		this.AddControl("Checkbox", "noResize", 0, row2 col3 "Check3 checked-1", "No thick border")
		this.AddControl("Checkbox", "noThinBorder", 0, row3 col3 "Check3 checked-1", "No thin border")
		this.AddControl("Checkbox", "noCaption", 0, row4 col3 "Check3 checked-1", "No caption")
		this.AddControl("Checkbox", "alwaysOnTop", 0, row5 col3 "Check3 checked-1", "Make always on top")
		this.AddControl("Checkbox", "disableTransition", 0, row6 col3 "Check3 checked-1", "No transition animation")
		this.AddControl("Checkbox", "info", this.infoCB.bind(this), row7 col3 "Check3 checked-1", "Info: Filled check means don't change")
		

		this.AddControl("Checkbox", "transCB", this.transCB.Bind(this), row4 col4 "Check3 checked-1", "Trans level:")											; Enable tranparency
		this.AddControl("edit", "transEdit", this.transEdit.Bind(this), row4_  "x+10 w55 center number limit3 disabled", 255)
		this.AddControl("Checkbox", "clickThroughCB", 0, row5 col4 "Check3 checked-1", "Enable click-through")													; Enable click-through
		this.AddControl("Checkbox", "transColorCB", this.transColorCB.Bind(this), row6 col4 "Check3 checked-1", "Trans color:")									; Enable transColor
		this.AddControl("edit", "transColorEdit", this.transColorEdit.Bind(this), row6_ "x+9 w55 center limit6 disabled", "FFFFFF")
		
		; DropDownLists
		Gui, Add, Text, % row1 col4, % "Misc:"
		this.AddControl("DropDownList", "topDDL", 0, row2 col4, "No choise made||Activate|Send to bottom|Maximise|Minimise")
		this.AddControl("DropDownList", "hideDDL", 0, row3 col4, "No choise made||Hide|Un-hide")
		
		Gui, Add, Button, % row7 col1 " w75 hwndApply", % "Apply"
		this.ApplyButton:=Apply
		gFunc := this.apply.Bind(this)
		GuiControl +g, % this.ApplyButton, % gFunc
		
		; Link tab
		Gui, Tab, 3
		col4:=" x455 " ; restore col
		; Plugin lists.
		caseOptions:="Never||Apply"
		this.didNotRefreshPluginList:=1 ; Listboxes are disabled until lists has been refreshed once, then this is set to zero, until forever.
		Gui, Add, Text, % row1 col1, % "Select plugin to run for case:"
		this.AddControl("DropDownList", "DDLcase1", 0, row1_ "x+10 w105", caseOptions)
		this.AddControl("ListBox", "lb_case1", this.selectLbItem.bind(this,1), row2 col1 " w250 r6 disabled","Please refresh")
		Gui, Add, Text, % row5 col1, % "Delay call with: (ms)"
		this.AddControl("Edit","case1Delay",0,row5_ " x215  w50 center number",0)
		this.AddControl("Edit","lb_case1_selected_edit",0,"disabled hidden ReadOnly")
		
		/* 
		;	Currently, it makes no sens to have this, since this plugin only has one case, i.e., apply.
		;	But the code is "ready" for other  cases, hence this is left for future convenience, should it be extended.
		;	There is also "check" for a second case in the code, these have not been commented out.
		Gui, Add, Text, % row1 col3, % "Select plugin to run for case:"
		this.AddControl("DropDownList", "DDLcase2", 0, row1_ "x+10 w105", caseOptions)
		this.AddControl("ListBox", "lb_case2", this.selectLbItem.bind(this,2), row2 col3 " w250 r6 disabled","Please refresh")
		this.AddControl("Edit","lb_case2_selected_edit",0,"disabled hidden ReadOnly")
		Gui, Add, Text, % row5 col3, % "Delay call with: (ms)"
		this.AddControl("Edit","case2Delay",0,row5_ " x535 w50 center number",0)
		*/
		
		Gui, Add, Button, % row6 col1 " w125 hwndRefreshButton", % "Refresh lists"
		this.RefreshButton:=RefreshButton
		gFunc := this.refreshPluginList.Bind(this)
		GuiControl +g, % this.RefreshButton, % gFunc
		
		Gui, Add, Text, % row6 col3 , % "Hotkey to stop all:"
		this.AddControl("InputButton","HotkeyStop", 0, this.forceAllOff.Bind(this), row6_ col4  " w130 h25")
		
		linkedToOptionsSame:="Apply||Ignore"
		Gui, Add, Text, % row7 col1 , % "When linked to by same type:"
		this.AddControl("DropDownList", "DDLlinkedToSame", 0, row7_ "x+10 w105", linkedToOptionsSame)
		
		linkedToOptionsOther:="Apply||Ignore"
		Gui, Add, Text, % row7 col3 , % "When linked to by other type:"
		this.AddControl("DropDownList", "DDLlinkedToOther", 0, row7_ "x+10 w105", linkedToOptionsOther)
		
		; Help tab
		Gui, Tab, 4
		Gui, add, text, % row1 col1, % "Author: Helgef"
		Gui, add, text, % row2 col1, % "Date: 2016-11-30"
		Gui, add, Link, % row3 col1, % "Instructions are available at: <a href=""https://autohotkey.com/boards/viewtopic.php?f=19&t=24538"">AutoHotkey.com forum.</a>"
		Gui, add, Link, % col1 " y+5", % "Credits to evilC for making <a href=""https://github.com/evilC/UCR"">UCR.</a>"
		Gui, add, text, % col1 "y+5 w500 +wrap" , % "Note:`nThis is a user plugin made for UCR. Neither the author of UCR nor the author of this plugin, is responsible for any outcome this piece of code yields."
	}

	onClose()
	{	
		WinShow, % "ahk_id " this.sId					; Show window when closing UCR. For safety
		GuiControl, -g, % this.pickButton
	
		GuiControl, -g, % this.sourceRadio1
		GuiControl, -g, % this.sourceRadio2
		GuiControl, -g, % this.sourceRadio3		
		
		GuiControl, -g, % this.SelectRectButton	
		
		GuiControl, -g, % this.ApplyButton
		
		this.extTimer:=""
		GuiControl, -g, % this.RefreshButton
		
		this.doNothingFunc:=""
		base.onClose() ;?
		return
	}
	
	; Gui functions.
	
	; Transparency gui handling.
	transCB(state)
	{
		GuiControl, % state=1?"Enable":"Disable", % this.GuiControls.transEdit.hwnd
		return
	}
	
	transColorCB(state)
	{
		GuiControl, % state=1?"Enable":"Disable", % this.GuiControls.transColorEdit.hwnd
		return
	}
	transEdit(val)
	{
		if (val>255)
			this.GuiControls.transEdit.Set(255)
		return
	}
	transColorEdit(val)
	{
		return	; Seems to trigger inf loop ?
		if val is not xdigit
			this.GuiControls.transColorEdit.Set("FFFFFF")
		if (val<0)
			this.GuiControls.transColorEdit.Set("000000")
		else if (val>0xFFFFFF)
			this.GuiControls.transColorEdit.Set("FFFFFF")
		return
	}
	
	infoCB(state)	; Check box example, info.
	{
		if (state=-1)
			this.GuiControls.info.Set("Info: Filled or gray means don't change this style")
		else if (state=1)
			this.GuiControls.info.Set("Info: Checked means set this style") 
		else if (state=0)
			this.GuiControls.info.Set("Info: Empty means disable this style")
		return
	}
	
	; DropDownList functions
	topDDL(state)
	{
		; State is 1 if called from updateStyle, 0 if called from restoreStyles
		; Options: No choise made||Activate|Send to bottom|Maximise|Minimise
		selection:=this.GuiControls.topDDL.Get()
		if (selection="No choise made")
			return
		else if (selection="Activate" && state)
			WinActivate, % "ahk_id " this.sId			
		else if (selection="Send to bottom" && state)
			WinSet, Bottom,, % "ahk_id " this.sId
		else if (selection="Maximise" && state)
			WinMaximize, % "ahk_id " this.sId
		else if (selection="Maximise" && !state)
			WinRestore,  % "ahk_id " this.sId
		else if (selection="Minimise" && state)
			WinMinimize, % "ahk_id " this.sId
		else if (selection="Minimise" && !state)
			WinRestore,  % "ahk_id " this.sId
		return
	}
	
	hideDDL(state)
	{
		; State is 1 if called from updateStyle, 0 if called from restoreStyles
		; Options No choise made||Hide
		; NOTE: Option removed, still using ddl 
		selection:=this.GuiControls.hideDDL.Get()
		if (selection="Un-hide")
			WinShow, % "ahk_id " this.sId
		else if (selection="Hide" && state)
			WinHide, % "ahk_id " this.sId
		else if (selection="Hide" && !state)
			WinShow, % "ahk_id " this.sId
		return
	}
	
	winBoxChanged(state)
	{
		; Enable / disable custom window coords depending on useCustomWinPlacement checkbox.
		GuiControl, % state?"Enable":"Disable", % this.GuiControls.cwb_x1.hwnd
		GuiControl, % state?"Enable":"Disable", % this.GuiControls.cwb_y1.hwnd
		GuiControl, % state?"Enable":"Disable", % this.GuiControls.cwb_w.hwnd
		GuiControl, % state?"Enable":"Disable", % this.GuiControls.cwb_h.hwnd
		GuiControl, % state?"Enable":"Disable", % this.SelectRectButton
		GuiControl, % state?"Enable":"Disable", % this.CWBText1
		GuiControl, % state?"Enable":"Disable", % this.CWBText2
		
		GuiControl, % !state?"Enable":"Disable", % this.GuiControls.fullscreen.hwnd
		GuiControl, % !state?"Enable":"Disable", % this.GuiControls.offScreen.hwnd
		
		return
	}
	
	; Select rect functions
	; Select custom window rectangle
	selectRect()
	{
		; this is called by the "Select area"-button. this.SelectRectButton
		KeyWait, LButton 							; Wait for LButton to be released.
		fn:=this.doNothingFunc						; Hotkey function
		Hotkey, If, 1
		Hotkey, LButton, % fn, On
		TrayTip,, % "Left click and drag over the area you want to zoom.",15,1
		KeyWait, LButton, d 						; Wait for LButton to be held down
		CoordMode, Mouse, Screen
		
		MouseGetPos,x,y,wum
		WinActivate, % "ahk_id " wum
		guiID:=this.makeDragBoxGui(x,y)				; Create the gui drag box.
		
		timerFunc:=ObjBindMethod(this, "dragRect", x,y,guiID)	; Timer routine for resizing the gui drag box.
		
		SetTimer, % timerFunc, 20
		; Wait for LButton to be released.
		KeyWait, LButton 
		; Delete the timer.
		SetTimer, % timerFunc, Delete 
		
		this.setDragBoxCoords(wum, guiID)			; Set up the correct coords.
				
		Hotkey, LButton, % fn, Off					; Turn off the LButton suppress
		Hotkey, If
		TrayTip,, % "Selection done!",10,1			; Show tray tip and do some fancy fade out.
		WinActivate, % "ahk_id " this.ucrHWND
		Loop,30 ; Fancy fade out
		{
			WinSet, Transparent, % 125-A_Index*5, % "ahk_id " guiID
			Sleep,10
		}
		Gui, %guiID%: Destroy						; Destroy drag box gui
		CoordMode, Mouse, Window 					; This doesn't really seem to be needed.
		return
	}
	
	doNothing() ; for suppress LButton in selectRect().
	{
		return
	}
	
	setDragBoxCoords(wum,guiID)
	{
		; Sets up the custom win rectangle edit boxes after a drag box has been completed.
		WinGetPos,dX,dY,dW,dH, % "ahk_id " guiID		; Get drag box gui pos and dimensions.
		
		; Update edit boxes
		this.GuiControls.cwb_x1.Set(dX)				
		this.GuiControls.cwb_y1.Set(dY)
		this.GuiControls.cwb_w.Set(dW)
		this.GuiControls.cwb_h.Set(dH)
		return
	}	
	
	makeDragBoxGui(x,y)
	{
		; Make the drag box gui, pop-up at location x,y
		; return hwnd to the new gui.
		Gui, new
		Gui, +HWNDguiID +ToolWindow +AlwaysOnTop -Caption
		Gui, %guiID%: Color, 7777FF 							; UCR purple.
		Gui, %guiID%: Show, x%x% y%y%
		WinSet, Transparent, 125, % "ahk_id " guiID				; Make drag box transparent.
		return guiID
	}
	
	dragRect(refX,refY,guiID)
	{
		; Function for resizing the drag box gui.
		; This is only called via timer, no need to reset WinDelay and CoordMode.
		CoordMode, Mouse, Screen
		MouseGetPos,x,y
		if (x<refX)
			this.swapVar(x,refX) 
		if (y<refY)
			this.swapVar(y,refY)
		w:=abs(refX-x)
		h:=abs(refY-y)
		SetWinDelay,-1
		WinMove, ahk_id %guiID%,,refX,refY,w,h
		return
	}
	
	swapVar(ByRef a,ByRef b)	; Standard swap variable value function
	{
		c:=b, b:=a, a:=c
		return
	}
	
	; For source radio buttons
	checkSourceRadio()
	{
		; Check the correct radio button, according to saved value in hidden edit box
		num:=this.GuiControls.SourceRadioEdit.Get()
		GuiControl,, % this.sourceRadio1, % num=1
		GuiControl,, % this.sourceRadio2, % num=2
		GuiControl,, % this.sourceRadio3, % num=3
		return
	}
	
	SourceRadioChanged()
	{		
		; Saves radio button selection to hidden edit
		GuiControlGet,num1,, % this.sourceRadio1
		GuiControlGet,num2,, % this.sourceRadio2
		GuiControlGet,num3,, % this.sourceRadio3
		Loop, 3
			if (num%A_Index% && (num:=A_Index))
				break
		this.GuiControls.SourceRadioEdit.Set(num) ; Hidden edit
		return
	}
	
	pickGame()
	{
		; Point and click routine to set up exe, title and hwnd for window to style.
		TrayTip,, % "Left-Click the game window`, click on UCR to abort.",30,1
		KeyWait, LButton
		KeyWait, LButton,D
		MouseGetPos,,,wum
		if (wum=this.ucrHWND) 										; User clicked UCR, abort.
		{
			TrayTip,, % "Aborted.",10,1
			return
		}
		WinActivate, % "ahk_id " this.ucrHWND 						; Activate UCR again.
		; Get window info
		WinGetTitle, title, ahk_id %wum%							; Get window title
		WinGet,exe, ProcessName, ahk_id %wum%
		; Set edit fields
		this.GuiControls.exe.Set(exe)
		this.GuiControls.title.Set(title)
		this.GuiControls.hwndEdit.Set(wum)
		TrayTip,, % "Done!`nSelected:`n" exe "`n" title,10,1
		this.settingChanged()
		return
	}

	fullscreen(state)
	{
		if state
			this.GuiControls.offScreen.Set(0)
		return
	}
	
	offScreen(state)
	{
		if state
			this.GuiControls.fullscreen.Set(0)
		return
	}
	
	; Apply and button functions.
	apply()
	{
		this.updateStyle(1)
		return
	}
	
	updateStyle(state)
	{
		if !state
			return
		DHW_Setting:=A_DetectHiddenWindows
		DetectHiddenWindows, On
		this.sId:=WinExist(this.GetGameTitle())			; Get source hWnd.
		if !this.sId									; If source doesn't exist, return
		{
			DetectHiddenWindows, % DHW_Setting
			return
		}
		
		if (this.GuiControls.noCaption.Get()!=-1)
			WinSet, Style, % this.GuiControls.noCaption.Get()? "-0xC00000":"+0xC00000", % "ahk_id " this.sId
		if (this.GuiControls.noThinBorder.Get()!=-1)
			WinSet, Style, % this.GuiControls.noThinBorder.Get()?"-0x800000":"+0x800000", % "ahk_id " this.sId
		if (this.GuiControls.noResize.Get()!=-1)
			WinSet, Style, % this.GuiControls.noResize.Get()? "-0x40000":"+0x40000", % "ahk_id " this.sId
		
		; Set desired position and dimension 
		if this.GuiControls.useCustomWinPlacement.Get()
		{
			; Set window to custom position and size.
			x:=this.GuiControls.cwb_x1.Get(), y:=this.GuiControls.cwb_y1.Get()
			w:=this.GuiControls.cwb_w.Get(),  h:=this.GuiControls.cwb_h.Get()
			WinMove, % "ahk_id " this.sId,,x,y,w,h
		}
		else if this.GuiControls.fullscreen.Get()
		{
			; Move window to 0,0 and resize to fit screen.
			WinMove, % "ahk_id " this.sId,,0,0,A_ScreenWidth,A_ScreenHeight
		}
		else if this.GuiControls.offScreen.Get()
		{
			; Set window y position to 10000, off screen, probably
			WinMove, % "ahk_id " this.sId,,,10000
		}
		
		if (this.GuiControls.alwaysOnTop.Get()!=-1)
			WinSet,AlwaysOnTop, % this.GuiControls.alwaysOnTop.Get()?"On":"Off",  % "ahk_id " this.sId
		
		if (this.GuiControls.disableTransition.Get()!=-1)
			this.Dwm_SetWindowAttributeTransistionDisable(this.sId,this.GuiControls.disableTransition.Get())
		
		; Handle tranparency and trans color
		; Only transColor or tranparency allowed.
		if (this.GuiControls.clickThroughCB.Get()!=-1)
			WinSet, ExStyle, % this.GuiControls.clickThroughCB.Get()=1?"+0x20":"-0x20", % "ahk_id " this.sId
			
		if (this.GuiControls.transColorCB.Get()!=-1)
		{
				WinSet, Transparent, Off, % "ahk_id " this.sId
				WinSet,	TransColor, % this.GuiControls.transColorCB.Get()=1?this.GuiControls.transColorEdit.Get():"Off",  % "ahk_id " this.sId
		}
		else if (this.GuiControls.transCB.Get()!=-1)
		{
				WinSet, TransColor, Off, % "ahk_id " this.sId
				WinSet,	Transparent, % this.GuiControls.transCB.Get()=1? this.GuiControls.transEdit.Get():"Off",  % "ahk_id " this.sId
		}

		
		this.topDDL(1)
		this.hideDDL(1)
		WinSet, Redraw,, % "ahk_id " this.sId
		DetectHiddenWindows, % DHW_Setting
		; ==  Link ==
		case:="Apply"
		this.linkTrigger(case)
		return
	}
	
	GetGameTitle()
	{
		; Source radio buttons
		GuiControlGet,button1,, % this.sourceRadio1	; Use game exe and title
		GuiControlGet,button2,, % this.sourceRadio2	; Use hwnd
		GuiControlGet,button3,, % this.sourceRadio3	; Use active window
		
		; If using active window and window is hidden or moved, restore
		if (button3 && this.sId!=WinActive("A"))
		{
			if this.wasMoved
				WinMove, % "ahk_id " this.sId,, this.x, this.y, this.w, this.h
			if this.wasHidden
				WinShow, % "ahk_id " this.sId
			this.wasMoved:=0
			this.wasHidden:=0
		}	
		if button1
		{
			exe:=this.GuiControls.exe.Get()
			exe:= RegExMatch(exe,".exe$")?exe:exe ".exe" ; Append .exe if needed
			wintitle:=this.GuiControls.title.Get()
			return wintitle " ahk_exe " exe
		}
		if (button2 && (hwnd:=this.GuiControls.hwndEdit.Get()))
			return "ahk_id " hwnd
		if (button3 && (hwnd:=WinActive("A")))
			return "ahk_id " hwnd
		Msgbox, 16, Error, Couldn't determine source.,1
		return 0
	}
	
	; DWM functions

	Dwm_SetWindowAttributeTransistionDisable(hwnd,onOff)
	{
		;
		;	DWMWA_TRANSITIONS_FORCEDISABLED=3
		;	Use with DwmSetWindowAttribute. Enables or forcibly disables DWM transitions.
		;	The pvAttribute parameter points to a value of TRUE to disable transitions or FALSE to enable transitions.
		;
		dwAttribute:=3
		cbAttribute:=4
		VarSetCapacity(pvAttribute,4,0)
		NumPut(onOff,pvAttribute,0,"Int")
		hr:=DllCall("Dwmapi.dll\DwmSetWindowAttribute", "Uint", hwnd, "Uint", dwAttribute, "Uint", &pvAttribute, "Uint", cbAttribute)
		return hr
	}
	
	; Link code.
	
	selectLbItem(num,val)
	{
		; Set hidden edit field to hold selected items in plugin lists.
		if (num=1)
			this.GuiControls.lb_case1_selected_edit.set(val)
		else if (num=2)
			this.GuiControls.lb_case2_selected_edit.set(val)
		return
	}
	
	refreshPluginList()
	{
		if this.didNotRefreshPluginList
		{
			this.didNotRefreshPluginList:=0
			GuiControl, % "Enable", % this.GuiControls.lb_case1.hwnd
			GuiControl, % "Enable", % this.GuiControls.lb_case2.hwnd
		}
		; Build list.
		pluginList:=" - None - |"
		for k, v in this.ParentProfile.Plugins
			pluginList.=this.linkTypes.HasKey(v.type)?"|" v.name:""
		this.pluginList:=pluginList
		
		; Empty lists.
		GuiControl,, % this.GuiControls.lb_case1.hwnd, % "|"
		GuiControl,, % this.GuiControls.lb_case2.hwnd, % "|"
		; Update.
		GuiControl,, % this.GuiControls.lb_case1.hwnd, % this.pluginList
		GuiControl,, % this.GuiControls.lb_case2.hwnd, % this.pluginList
		; Restore selection.
		this.GuiControls.lb_case1.Set(this.GuiControls.lb_case1_selected_edit.Get())
		this.GuiControls.lb_case2.Set(this.GuiControls.lb_case2_selected_edit.Get())	
		return
	}
	
	externalCall(vars*)
	{
		; For now, only call with plugins preset settings. I.e., vars* is empty.
		if this.foff 			; Forced off, return
			return
		; Possible "actions" are: "Apply||Ignore"
		if (vars[1].type=this.type)
			action:=this.GuiControls.DDLlinkedToSame.Get() 	; Match DDLlinkedToSame
		else
			action:=this.GuiControls.DDLlinkedToOther.Get()	; Match DDLlinkedToOther
		
		if (action="Ignore")
			return
		else if (action="Apply")
			this.apply()
		return
	}
	
	forceOff()
	{
		; Force the plugin off. Depending on what the plugin does, this might not need to do anything.
		extTimer:=this.extTimer
		try
			SetTimer, % extTimer, Delete	; Delete timer if it exists.
		this.toggleState:=0					; ensure correct toggle state.
		this.restoreStyles()
		return
	}
	
	forceAllOff(state)
	{
		; Shuts down all (linkTypes) plugins in current profile.
		; When all has been forced off, call this function again to re-enable all.
		if !state
			return
		if this.foff
		{
			for k, v in this.ParentProfile.Plugins
				if this.linkTypes.HasKey(v.type)
					v.foff:=0
			return
		}
		for k, v in this.ParentProfile.Plugins
			if this.linkTypes.HasKey(v.type)
				v.foff:=1,v.forceOff()
		return
	}
	
	linkTrigger(case)
	{
		; Call another plugin depending on 'case'
		; 'case' is one of the options in the DDLcase1 or DDLcase2 DropDownLists. I.e., a string.
		if !(case:=this.confirmCase(case))	
			return
		; Case confirmed and converted to numeric, 1 or 2.
		plugin:=this.getExternalPlugin(case)
		if plugin
		{
			extParams:=this.getCaseParams(case)
			extTimer:=ObjBindMethod(plugin,"externalCall",extParams*)
			this.extTimer:=extTimer			; Needed to shut down chain.
			if (case=1)
				SetTimer, % extTimer, % (del:=this.GuiControls.case1Delay.Get())?-del:-1
			else if (case=2)
				SetTimer, % extTimer, % (del:=this.GuiControls.case2Delay.Get())?-del:-1
		}
		return		
	}
	
	getCaseParams(case)
	{
		; Create an array of params to be passed to the external plugin.
		; params[1] should contain a reference to the caller.
		params:=[]
		params[1]:=this
		return params
	}
	
	confirmCase(case)
	{
		; Function to confirm the current event is selected as one case that will trigger another plugin.
		if (case=this.GuiControls.DDLcase1.Get())
			return 1
		else if (case=this.GuiControls.DDLcase2.Get())
			return 2
		return 0 ; Case not confirmed, no external plugin should be called
	}
	
	getExternalPlugin(case)
	{
		; Check if an external plugin call should be made.
		; If, return a reference to that plugin.
		; case indicates which case occured, fetch correct plugin.
		if (case=1)
			pluginName:=this.GuiControls.lb_case1_selected_edit.Get() 
		else if (case=2)
			pluginName:=this.GuiControls.lb_case2_selected_edit.Get() 

		if (pluginName=" - None - " || pluginName="") 	; No plugin should be called
			return

		for k, plugin in this.ParentProfile.Plugins		; Search for plugin in the current profile.
			if (plugin.name=pluginName)
				return plugin
		return 0 ; The plugin wasn't found.
	}
	
	; Used by the hotkey command in selectRect()
	#If, 1	
	#If
}
Last edited by Helgef on 03 Jan 2017, 18:03, edited 1 time in total.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [UCR Plugin] Zoom - Zoom in or out any window.

03 Jan 2017, 17:59

CodeThread
A variant of the built-in Code Runner plugin. This plugin gives option to run (AHK_H) code in a new thread. Can be used for, eg, creating hotkeys that runs in parallel. For example, running this code in one script, would only allow for one of the ToolTip to be updated at a time.

Code: Select all

a::
	while GetKeyState(A_ThisHotkey)
		ToolTip, % A_TickCount,0,0,1
return
b::
	while GetKeyState(A_ThisHotkey)
		ToolTip, % A_TickCount,0,50,2
return
While putting each hotkey in a new thread, allows both to be updated simultaneously.
Some features:
  • Run code in new thread or wait for it to finish
  • Trigger code to start/stop via hotkey or button. (Wait to finish code cannot be stopped by other means than closing UCR)
  • Option to select tray icon for new thread, or to omit it.
  • Edit control has tab stops and and monospaced font
Known limitations:
  • Very limited testing.
Download.
Save as CodeThread.ahk

Code: Select all

class CodeThread extends _UCR.Classes.Plugin
{
	; Author: Helgef
	; Date: 2016-11-01
	; Instructions at: https://autohotkey.com/boards/viewtopic.php?f=19&t=24538
	; Credits to evilC for making UCR (https://github.com/evilC/UCR)
	; UCR
	Type := "CodeThread"
	Description := "Execute code in a new thread."
	; Class variables
	static linkTypes:={"Zoom":0, "CodeThread":0, "WindowStyler":0}	; List of plugin types that can be linked to.
	
	; Instance variables
	
	toggleState:=0							; Initially, the plugin is off.
	pluginList:=" - None - "				; List of plugins, for listbox.
	; Mandatory method.
	Init()
	{
		
		; Set up timer functions
		this.extTimer:=ObjBindMethod(this,"doNothing")
		this.foff:=0 ; This is needed to force all plugins to stop
		
		; Gui
		; Rows for gui placement
		row1:=" y35 ",  	row1_:=" y32 "
		row2:=" y65 ",  	row2_:=" y62 "
		row3:=" y95 ",  	row3_:=" y92 "
		row4:=" y125 ", 	row4_:=" y123 "
		row5:=" y155 ", 	row5_:=" y153 "
		row6:=" y185 ", 	row6_:=" y183 "
		
		; row7:= 215, is the natural choise of heigth
		
		; Columns for gui placement
		col1:=" x15 ",  	col2:=" x200 ",	col3:=" x335 ",	col4:=" x455 "	col5:=" x535 "
		
		; Main Tab
		Gui, Add, Tab2, w650 h215, % "Main|Code|Link|Help"
		Gui, Add, Text, % row1 col1 , % "Hotkey to toggle start/stop:"
		this.AddControl("InputButton","HotkeyToggle", 0, this.toggle.Bind(this), row1_ col2  " w125 h25")
		
		Gui, Add, Text, % row2 col1 , % "Hotkey to stop all:"
		this.AddControl("InputButton","HotkeyStop", 0, this.forceAllOff.Bind(this), row2_ col2  " w125 h25")
		
		Gui, Add, Text, % row3 col1 , % "Thread icon dll source:"
		this.AddControl("Edit","IconDllEdit",0, row3_ col2  " w125 h25 center", "shell32.dll")
		
		Gui, Add, Text, % row4 col1 , % "Thread icon number:"
		this.AddControl("Edit","IconNumEdit", this.iconPreview.Bind(this), row4_ col2  " w125 h25 center")
		Gui, Add, Text, % row5 col1 , % "Thread icon preview:"
		Gui, Add, Picture, % row5 col2 " hwndiconPic w64 h64"
		this.iconPic:=iconPic
		
		; Code tab
		Gui, Tab, 2
		
		; Make tab stops
		Tn:=""
		Loop, 50
			Tn.=" T" A_Index*8
	
		Gui, Font, s8, Courier New
		this.AddControl("Edit", "code", 0, row1 col1 " r11 w500 WantTab -Wrap Hscroll " Tn )
		Gui, Font
		Gui, Add, Text, % row1 col5 " center", % "Run options:"
		this.AddControl("Checkbox", "cb1",this.cbSetting.bind(this,1),row2 col5 , "Wait to finish.")
		this.AddControl("Checkbox", "cb2",this.cbSetting.bind(this,2),row3 col5 "checked" , "New thread.")
		this.AddControl("Checkbox", "cb3",this.cbSetting.bind(this,3),row4 col5 , "Hide tray icon.")
		
		; Add start stop buttons
		Gui, Add, Button, % row5 col5 " w115 hwndExecuteButton", % "Execute"
		this.ExecuteButton:=ExecuteButton
		gFunc := this.toggle.Bind(this,1)
		GuiControl +g, % this.ExecuteButton, % gFunc
		
		Gui, Add, Button, % row6 col5 " w115 hwndStopButton disabled", % "Stop thread"
		this.StopButton:=StopButton
		gFunc := this.closeThread.Bind(this)
		GuiControl +g, % this.StopButton, % gFunc
		
		; Link tab
		; Plugin lists.
		Gui, Tab, 3
		Gui, Add, Text, % row1 col1, % "Select plugin to run on finish:"
		this.AddControl("ListBox", "lb_find", this.selectLbItem.bind(this,1), row2 col1 " w250 r6", this.pluginList)
		Gui, Add, Text, % row5 col1, % "Delay call with: (ms)"
		this.AddControl("Edit","findDelay",0,row5_ " x215  w50 center number",0)
		this.AddControl("Edit","lb_find_selected_edit",0,"disabled hidden ReadOnly")
		
		Gui, Add, Button, % row6 col1 " w125 hwndRefreshButton", % "Refresh lists"
		this.RefreshButton:=RefreshButton
		gFunc := this.refreshPluginList.Bind(this)
		GuiControl +g, % this.RefreshButton, % gFunc
		
		
		Gui, Add, Text, % row1 col3 , % "Select action when this plugin is triggered via link:"
		linkedToOptionsSame:="Toggle||Turn on|Turn off"
		Gui, Add, Text, % row2 col3 , % "When linked to by same type:"
		this.AddControl("DropDownList", "DDLlinkedToSame", 0, row2_ "x+10 w105", linkedToOptionsSame)
		
		linkedToOptionsOther:="Toggle||Turn on|Turn off"
		Gui, Add, Text, % row3 col3, % "When linked to by other type:"
		this.AddControl("DropDownList", "DDLlinkedToOther", 0, row3_ "x+10 w105", linkedToOptionsOther)
		
		
		; Help tab
		Gui, Tab, 4
		Gui, Tab, 4
		Gui, add, text, % row1 col1, % "Author: Helgef"
		Gui, add, text, % row2 col1, % "Date: 2016-11-01"
		Gui, add, Link, % row3 col1, % "Instructions are available at: <a href=""https://autohotkey.com/boards/viewtopic.php?f=19&t=24538"">AutoHotkey.com forum.</a>"
		Gui, add, Link, % col1 " y+5", % "Credits to evilC for making <a href=""https://github.com/evilC/UCR"">UCR.</a>"
		Gui, add, text, % col1 "y+5 w500 +wrap" , % "Note:`nThis is a user plugin made for UCR. Neither the author of UCR nor the author of this plugin, is responsible for any outcome this piece of code yields."
		
		; Misc.
		this.threadTrayTipCode := "Menu, Tray, Tip, " . this.name . "`n" ; This code is added to new threads to make it easier to identify which tray icon is from which code.
	}
	
	onClose()
	{
		if this.extTimer
		{
			fn:=this.extTimer
			try
				SetTimer, % fn, delete
			this.extTimer:=""
		}
		GuiControl -g, % this.ExecuteButton
		GuiControl -g, % this.StopButton
		GuiControl -g, % this.RefreshButton
		this.closeThread()
		base.onClose() ;?
		return
	}
	
	; Optional methods
	
	OnInActive()
	{
		this.forceOff()
		return
	}
	
	; Gui functions
	
	iconPreview(val)
	{
		; Show a preview of the selected icon.
		if (val="")
			return
		GuiControl,, % this.iconPic, % "*icon" val " *w *h " this.GuiControls.IconDllEdit.get()
		return
	}
	
	cbSetting(val,state)
	{
		; Forces only one checkbox to be checked. Instead of radios since they doesn't pereserve settings.
		if (val=3)
			return
		this.GuiControls.cb1.set(val==1 && state || val==2 && !state,,,false) ; fire_callback:=false to avoid inf recurse.
		this.GuiControls.cb2.set(val==2 && state || val==1 && !state,,,false)
		GuiControl,  % this.GuiControls.cb2.get() && !this.toggleState ? "Enable" : "Disable", % this.GuiControls.cb3.hwnd 	; Disable execute button when toggled on, only for visual.
		GuiControl,  % this.GuiControls.cb2.get() &&  this.toggleState ? "Enable" : "Disable", % this.StopButton			; Stop button only available for new thread setting.
		return
	}
		
	selectLbItem(num,val)
	{
		; Set hidden edit field to hold selected items in plugin lists.
		if num=1
			this.GuiControls.lb_find_selected_edit.set(val)
		return
	}
	
	refreshPluginList()
	{
		; Build list.
		pluginList:=" - None - |"
		for k, v in this.ParentProfile.Plugins
			pluginList.=this.linkTypes.HasKey(v.type)?"|" v.name:""
		this.pluginList:=pluginList
		
		; Empty lists.
		GuiControl,, % this.GuiControls.lb_find.hwnd, % "|"
		GuiControl,, % this.GuiControls.lb_fail.hwnd, % "|"
		; Update.
		GuiControl,, % this.GuiControls.lb_find.hwnd, % this.pluginList
		GuiControl,, % this.GuiControls.lb_fail.hwnd, % this.pluginList
		; Restore selection.
		this.GuiControls.lb_find.Set(this.GuiControls.lb_find_selected_edit.Get())
		this.GuiControls.lb_fail.Set(this.GuiControls.lb_fail_selected_edit.Get())	
		return
	}
	
	; Instance methods.
	toggle(state)
	{
		if (state=0)	 						 ; Release
			return
		this.toggleState:=!this.toggleState	 ; Toggle
		
		this.controlToggle(0)
		if this.toggleState
		{
			; It will be switched on, fetch some settings.
			if this.GuiControls.cb3.get()
				code:="#NoTrayIcon`n"
			else if this.GuiControls.cb2.get()
				code:= this.threadTrayTipCode
			
			if (this.GuiControls.cb2.get() && iconNum:=this.GuiControls.IconNumEdit.Get())
				code.="try`n`tMenu,Tray,Icon," . ((dll:=this.GuiControls.IconDllEdit.Get())!="" ? dll : "Shell32.dll") . "," . iconNum . "`n"
			code.=this.GuiControls.code.get()
			if this.GuiControls.cb1.get()
				AhkExec(code), this.toggleState:=0
			else
				this.thread:=AhkThread(code)
			this.controlToggle(1)
			this.linkTrigger()
			if (this.thread && this.thread.ahkReady())	; When the thread is finished, the appropiate buttons should be reaneabled.
			{
				t1:=A_TickCount
				while (!this.thread.ahkgetvar.A_ScriptHwnd && A_TickCount-t1<750){ 	; Wait 0.75 seconds for script to start exist
				}																	; Note: Instead one could force a "_clever" title onto the this.thread.ahkgetvar.A_ScriptHwnd hidden window, and wait for it.
				if (this.thread.ahkReady() && scriptHwnd:=this.thread.ahkgetvar.A_ScriptHwnd)	; Check if it is still running
				{
					this.threadWasManuallyClosed:=0
					timerFunc := ObjBindMethod(this, "waitCloseThread", scriptHwnd)
					SetTimer, % timerFunc, -1 
				}
			}
			else if this.thread
			{
				GuiControl,  % "Enable" , % this.ExecuteButton									
				GuiControl,  % "Disable", % this.StopButton		
				this.closeThread()
			}
		}
		else 
		{
			this.closeThread()
			this.controlToggle(1)
		}
		return
	}
	
	waitCloseThread(id)
	{
		try
			SetTimer,, delete
		DetectHiddenWindows, On
		WinWaitClose, % "ahk_id " id
		if this.threadWasManuallyClosed
			return this.threadWasManuallyClosed:=0
		this.toggleState:=0 							;	if the thread finishes, toggleState should be zero
		this.controlToggle(1)
		return
	}
	
	controlToggle(runComplete)
	{	
		; Toggles enable/disable for some controls, mostly for visual
		GuiControl,  % !this.toggleState ? "Enable" : "Disable", % this.ExecuteButton									; Disable execute button when toggled on, only for visual.
		GuiControl,  %  this.toggleState && this.GuiControls.cb2.get() ? "Enable" : "Disable", % this.StopButton		; Stop button only available for new thread setting.
		
		GuiControl,  % runComplete ? "Enable" : "Disable", % this.GuiControls.cb1.hwnd									; Disable/enable check buttons before run
		GuiControl,  % runComplete ? "Enable" : "Disable", % this.GuiControls.cb2.hwnd									; 
		GuiControl,  % runComplete && this.GuiControls.cb2.get() ? "Enable" : "Disable", % this.GuiControls.cb3.hwnd	; 
		return
	}
	
	closeThread()
	{
		if !this.thread
			return
		this.threadWasManuallyClosed:=1
		this.thread.AhkTerminate()
		AhkThread_Free(this.thread)
		this.thread:=""
		this.toggleState:=0
		this.controlToggle(1)
		return
	}
	
	externalCall(vars*)
	{
		; available actions -> "Toggle||Turn on|Turn off"
		; vars[1] should hold a reference to the plugin that called this one, i.e., its type is available through vars[1].type
		
		if (vars[1].type=this.type)
			action:=this.GuiControls.DDLlinkedToSame.Get() 	; Match DDLlinkedToSame
		else
			action:=this.GuiControls.DDLlinkedToOther.Get()	; Match DDLlinkedToOther
			
		if (action="Toggle")
			this.toggle(1)									; Toggle!
		else if (action="Turn on" && !this.toggleState)
			this.toggle(1)									; Toggle on if off
		else if (action="Turn off" && this.toggleState)
			this.toggle(1)									; Toggle off if on
		return
	}
	
	forceOff()
	{
		; Force the timers off
		this.closeThread()
		return
	}
	
	forceAllOff(state,part:=1)
	{
		; Shuts down all (linkTypes) plugins in current profile.
		; This is awkward.
		if !state
			return
		for k, v in this.ParentProfile.Plugins
			if this.linkTypes.HasKey(v.type)
				v.foff:=part, v.deleteTimer:=1, v.forceOff(), oneLinkFound:=1
		if (oneLinkFound && part)
		{
			part2:=ObjBindMethod(this,"forceAllOff",1,0)
			SetTimer, % part2, -100
		}
		return
	}
	
	
	linkTrigger()
	{
		; Trigger link?
		plugin:=this.getExternalPlugin()
		if plugin
		{
			extParams:=this.getCaseParams()
			extTimer:=ObjBindMethod(plugin,"externalCall",extParams*)
			this.extTimer:=extTimer 				; Needed to shut down chain.
			delay:=this.GuiControls.findDelay.Get() ? -this.GuiControls.findDelay.Get():-1 	; Do not allow 0, I guess negative is ok, but use with caution.
			SetTimer, % extTimer, % delay 
		}
		return
	}
	
	getCaseParams()
	{
		; Create an array of params to be passed to the external plugin.
		; params[1] should contain a reference to the caller.
		params:=[]
		params[1]:=this
		return params
	}
	
	getExternalPlugin()
	{
		; Check if an external plugin call should be made.
		; Find is a misnomer, it is due to copying this code from other plugin. 
		pluginName:=this.GuiControls.lb_find.Get()
		if (pluginName=" - None - " || pluginName="") ; No plugin should be called
			return

		for k, plugin in this.ParentProfile.Plugins
			if plugin.name=pluginName
				return plugin
		return 0 ; The plugin wasn't found.
	}
	
	doNothing()
	{
		return
	}
	
}
Last edited by Helgef on 03 Jan 2017, 18:02, edited 1 time in total.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [UCR Plugin] Zoom - Zoom in or out any window.

03 Jan 2017, 18:01

Developer plugin
A very simple plugin that facilitates (developer) usage of UCR. Recomended to be initialised in the SuperGlobal profile.
All features, via hotkeys:
  • Reload UCR
  • Activate UCR main window
  • Save settings
Download.
Save as developer.ahk

Code: Select all

class developer extends _UCR.Classes.Plugin
{
	type:="Developer"
	description:="Development plugin - Reload, Activate, Save"
	init()
	{
		Gui, Add, Text, y10, % "Reload UCR"
		this.AddControl("InputButton", "reload",0,this.reload.bind(this), "x+10 yp-5 w125 h25")
		Gui, Add, Text, y10 x+10, % "Activate UCR"
		this.AddControl("InputButton", "activate",0,this.activate.bind(this), "x+10 yp-5 w125 h25")
		Gui, Add, Text, y10 x+10, % "Save settings"
		this.AddControl("InputButton", "save",0,this.save.bind(this), "x+10 yp-5 w125 h25")
	}
	
	reload(state)
	{
		if !state
			return
		else
			reload
		return
	}
	
	activate(state)
	{
		if !state
			return
		else
			WinActivate, % "ahk_id " UCR.hwnd
		return
	}
	
	save(state)
	{
		if !state
			return
		UCR.__SaveSettings()
	}
}
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: [UCR Plugins] Zoom and a few more.

11 Jan 2017, 17:06

I am intrigued by this Link system you have.

What is the purpose of the "When linked to by same type / different type" options?
And similarly the "Select plugin to run for case" option in the WindowStyler

Being able to reference plugins from one another has always been something I wanted to introduce, but I have never really examined the kind of use-cases that I would like to support. A basic plugin selector would probably be fairly easy to implement - the profile select control and associated menus could quite easily be expanded to accommodate selection of plugins, and it could work in a similar way - ie you get a callback if something about the linked plugin changed (Name or Path).

Also, bear in mind that if doing this, you should probably reference plugins by their IDs, because at some point I will also be adding the ability to rename plugins. ID will remain constant, even if the plugin moves to another profile (Another planned feature).
Guest

Re: [UCR Plugins] Zoom and a few more.

12 Jan 2017, 12:57

evilC wrote: What is the purpose of the "When linked to by same type / different type" options?
I understand that it is not obvious :lol:
I'll try to explain with an example.
Let's say you have two Zoom plugins in a profile, A, and B. Now, if you set up plugin A like,Link -> Select Plugin to run for case -> Zoom in and select plugin B in the listbox below, that means that when plugin A is zoomed in, plugin in B will be called, and what will happen when plugin B is called from plugin A is determined by your choise in the When linked to by same type dropdown list of plugin B. So if you for example chooses plugin B to Match case, it will do the same thing as the plugin who called it did, in case of being linked to by plugin A, it would also zoom in. And this is the reason why the When linked to by different type dropdown list also exists, because if a Zoom plugin is called by a WindowStyler, you can't match cases.
evilC wrote: And similarly the "Select plugin to run for case" option in the WindowStyler
Originally, I intended the WindowStyler to be able to toggle between new style and original, but in the end it just does apply settings. So the only reason for having that dropdown list for the WindowStyler is that you can also select Never, which basically means disable linking.

The reason the linking system looks like it does, is because it comes from the image/pixel search plugin we briefly talked about some time ago, there it would make more sense because you have the case of finding or not finding the image/pixel, i.e, two cases, select one plugin to call for either case. So you get a chain of image/pixel searches that can trigger some event, eg, a key-macro.
evilC wrote: Being able to reference plugins from one another has always been something I wanted to introduce, but I have never really examined the kind of use-cases that I would like to support. A basic plugin selector would probably be fairly easy to implement - the profile select control and associated menus could quite easily be expanded to accommodate selection of plugins, and it could work in a similar way - ie you get a callback if something about the linked plugin changed (Name or Path).
All my linkable plugins have an externalCall(vars*) function, it is this function that is called, and then the called plugin handles the rest from there, depending on the settings. I originally intended, and to some extent implemented, that the caller should pass parameters to the linked plugin, via vars*, but that was bad idea, it is much better for the called plugin to simply recieve a reference to the caller, and fetch whatever it needs from the reference, it makes adding new linkable plugins much easier. For example, let's say you want to have some overlay that displays axis or button states for your remapper plugins, then an Overlay plugin could be called when, eg, the axis state of a ButtonToAxis plugin is changed, then it would be up to the overlay plugin to display the new state, hence you wouldn't need to make overlay options for all your remapper plugins. You just make one overlay plugin that handles whatever is being linked to it.
evilC wrote: Also, bear in mind that if doing this, you should probably reference plugins by their IDs, because at some point I will also be adding the ability to rename plugins. ID will remain constant, even if the plugin moves to another profile (Another planned feature).
At some point I did consider using the id, I'm not sure why I ended up using their names instead. I'll keep it in mind.

I guess the mess of this post reflects the mess of my implementation, feel free to ask whatever you didn't understand and point out whatever I missed to answer, cheers! ;)
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [UCR Plugins] Zoom and a few more.

12 Jan 2017, 12:59

I did reply, but I wasn't logged in, I think my reply is waiting for a moderator to approve.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [UCR Plugins] Zoom and a few more.

10 Feb 2017, 18:59

Actions per minute (APM) and Pixel per second (PPS) counter
This is a plugin for evaluating game and/or office performance, with respect to the number of keyboard actions per minute and mouse pixels moved per second. You might be surprised how many pixels you are moving :crazy:

Main statistics APM/PPS:
  • Average APM/PPS, your average speed for the current run of the plugin.
  • Current APM/PPS, your speed based on the last x ms. Can be change via plugin GUI.
  • Top APM/PPS, the highest current APM/PPS achieved.
  • Total actions, the sum of all actions/pixels moved (Separately ofc).

You can review your performance, in the plugin GUI,
Gif preview
and via a customisable overlay,
Gif preview
Transcolor on background, border around overlay, from left to right, Average Apm, Current Apm, Total actions, Time elapsed.

Setup options for the overlay are as shown below,
Image
Overlay options. Cramped GUI.

Extended performace report
After the plugin has run, you can view a more detailed report with extended statistics and (optional) plotting of the session,
report.png
report.png (160.25 KiB) Viewed 18726 times
Plots needs SVGraph, see credits and install instructions.

Download and Installation
Download:
APM.ahk
(53.77 KiB) Downloaded 424 times
and place in UCR\Plugins\User.

If you want the plots in the report, you need to download the files for SVGraph.
You need to place four files in UCR\Libraries\SVGraph, the files are,
  • SVGraph.ahk
  • SVGraph.js
  • SVGraph.html
  • d3.v4.js
Note: The plugin runs without SVGraph, but then you don't get the plots.

Misc features
  • PPS can be disabled, but not APM. See next item for comment.
  • The list of actions to consider can be modified via, Settings->Open key setup. Here, all keys can be deactivated, and hence apm is not measured.
  • There are two methods for measuring pixel movements, the regular UCR mouse delta, recommended, and also via (experimental and not completely evaluated) low level mouse hook, might be better for office use, uses less cpu as far my testing has showed.
  • Sampling rate and update frequency, as well as Current APM interval can be modified via the plugin's GUI.
  • Reports can be saved to file, and loaded back later. Note: Before you can save a report you need to show it once.
  • Sound beep on toggle :beard:
Known issues and limitations
  • No pause.
  • No hotkey to show/hide overlay during a session.
  • File size seems acceptable, ~5 hours with a sampling rate of 5 per second yielded a 75 kb file. Having a really high sampling rate going for a long time could take up a lot of memory. Default sampling rate is 1 per second, it's probably fine. Disabling plotting via checkbox or by not including the plot files in the first place, minimises memory usage.
  • Registers all actions as hotkey ~*key, interference with UCR hotkeys has not been evaluated.
  • The overlay only shows numbers, what they mean is defined by the same order as the options for showing them in the overlay options. From left to right, or top bottom if horizontal option is unticked.
Comments on implementation.
The plugin has a nested counter class, this class handles the calculations for the current and average APM/PPS. It is independent from UCR and can be used in any ahk script for counting anything, eg, feed it words and you have a word per minute counter, with your current typing speed.

Code: Select all

class counter
{
	; Feel free to use this in any context you like.
	; Count per time interval (cpti) class
	; Counts average and current number of events per time interval
	; 	
	;	Input:
	;			N, integer 				 The current apti is calculated based on the N last calls to this.calc(). 
	;			interval, number>0, default 60	(apm)
	;			Interval examples:
	;							1		per second
	;							60 		per minute
	;							3600	per hour
	; 			
	static f:=counter.getQPF()
	__new(N,interval:=60)
	{
		DllCall("QueryPerformanceCounter", "Int64P", tic)
		this.startTime:=tic
		this.N:=N											;
		this.interval:=interval
		this.counts:=[]
		Loop, % N
			this.counts.Push({ctr:0,t:tic})
		this.currentActions:=0								; The current number of actions
			
		this.totalCtr:=0									; For the average count
		this.currentCtr:=0									; For the current count
		this.events:=Object()								; Count individual events, needn't be specified when calling addCount()
		this.events.SetCapacity(256)
	}
		
	addCount(count,event:="")
	{
		; Increments the counters and event count.
		event!="" && this.events.hasKey(event) ? this.events[event]+=count : this.events[event]:=count
		return this.totalCtr+=count, this.currentCtr+=count
	}
	
	calc()
	{
		; Calculates the average and current cpm
		DllCall("QueryPerformanceCounter", "Int64P", tic)										; Get timestamp
		; Average cpti
		average:= this.totalCtr / ((tic - this.startTime)/this.f) * this.interval				; The average is the total count / total time 
		; Current cpti
		this.counts.push({ctr:this.currentCtr, t:tic})											; Store current count and timestamp
		oldCount:=this.counts.RemoveAt(1)
		this.currentActions-=oldCount.ctr														; The oldest addition is removed and subtracted
		this.currentActions+=this.currentCtr													; The new is added
		this.currentCtr:=0																		; Reset current ctr.
		current:=this.currentActions / ((tic - this.counts[1].t)/counter.f) * this.interval
		return [current, average, tic] 															; returns: [current cpti, average cpti, tic]	
	}
		
	getEvents()
		{
		return this.events
	}
	
	getTotalCount()
	{
		return this.totalCtr
	}
		
	getQPF()
	{
		DllCall("QueryPerformanceFrequency", "Int64P", qpf)	; QueryPerformanceFrequency.
		return qpf
	}
}
The rest of the code is mostly settings and report handling.

Credits

Good luck. Cheers!
Edit: English
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [UCR Plugins] Zoom. New (2017-02-11): APM - Action per minute counter.

20 Feb 2017, 10:14

Cheers!

I guess you would, for the joy-sens graphs you mentioned in the SVGraph thread. The QueryPerformanceCounter stuff sure is handy at times,
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [UCR Plugins] Zoom. New (2017-02-11): APM - Action per minute counter.

03 Mar 2017, 17:40

Cursor
Conceptual plugin. Allows multiple mouse cursors to be used simultaneously.

Some features:
  • Use multiple cursors with multiple mice, simultaneously.
  • Multiple cursors for each mouse.
  • Sensitivity setting per each cursor.
  • Cycle through cursors.
  • Buttons considered: Left, Right, Middle, XButton1, XButton2, WheelUp, WheelDown.
  • Confine cursor to any rectangle on screen.
Preview.
Image
Moving around and clicking two cursors, using two mice. :crazy:
Gif made with shareX.

How to use.
  • Click the Select mouse button with the mouse you want to use.
  • Move the mouse.
  • The mouse id should show in the edit field next to the button.
  • Select hotkey, toggle it on.
  • Optionally, set the sensitivity for the cursor.
Download.
Download:
Cursor.ahk
(20.5 KiB) Downloaded 451 times
and place in UCR\Plugins\User.

Known limitations:
  • There is no such thing as simultaneously draging.
  • There is no concept of multiple cursors in windows, this is a custom implementation.
  • Doesn't fully handle always on top for the cursors.
  • WheelLeft and WheelRight is not handled.
  • Due to windows not updating the mouse cursor quick enough, you will get the wrong cursor image under some circumstances.
  • Clicking a mouse button with mouse A at point a, and the same button with mouse B at point b (while still holding the button on mouse A), makes a click-drag between a and b. This is easy to fix. I might do it, if there is any interest :yawn:
  • There might be unexpected results if you have instances of this plugin across multiple UCR profiles.
  • One directional cycle. :arrow:
  • For testing purposes, the UCR window itself isn't the best environment, due to the single threaded nature of AHK. (It works mostly fine there though.)
  • Very limited testing. Tested only with two mice. Win7.
Misc.
The plugin uses a slightly modifed version of MouseDelta.
Feel free to use this in which ever way you like. :wave:

Edit: Bug fix, code updated 2017-03-04
Last edited by Helgef on 04 Mar 2017, 16:17, edited 1 time in total.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [UCR Plugins] Zoom. New (2017-02-11): APM - Action per minute counter.

04 Mar 2017, 03:01

xZomBie wrote:EitherMouse
Hi, xZomBie, thank you for your comment, EitherMouse seems excellent, however, as far as I understand it doesn't apply to this concept. (With reference to the Cursor plugin.)

Cheers.
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: [UCR Plugins] Latest: Cursor - Multiple mice/cursors. (2017-02-11): APM - Action per minute counter.

04 Mar 2017, 12:55

Yeah, not the same as EitherMouse.

It does not work on my PC though, maybe because of my multi-monitor setup?
When activated, the mouse gets moved to the bottom-left corner of my monitor and i cannot move it.

If I comment out these lines. I see some life in it (can move real cursor), but the other mouse does not move the fake cursor:

Code: Select all

				cur.x:= cur.x>cur.MaxX?cur.MaxX:(cur.x<cur.MinX?cur.MinX:cur.x)				; Confine
				cur.y:= cur.y>cur.MaxY?cur.MaxY:(cur.y<cur.MinY?cur.MinY:cur.y)
Here is my monitor setup:

Code: Select all

MonitorCount: 5
MonitorPrimary: 4

Monitor #1 coords:
Left: -1024
Right: 0
Top: -87
Bottom: 1193

Monitor #2 coords:
Left: -2048
Right: -1024
Top: -97
Bottom: 1183

Monitor #3 coords:
Left: 2944
Right: 3968
Top: -92
Bottom: 1188

Monitor #4 coords:
Left: 0
Right: 1920
Top: 0
Bottom: 1200

Monitor #5 coords:
Left: 1920
Right: 2944
Top: -92
Bottom: 1188
Got using:

Code: Select all

sysget, ct, MonitorCount
sysget, pri, MonitorPrimary
out .= "MonitorCount: " ct "`n"
out .= "MonitorPrimary: " pri "`n"
Loop % ct {
	Sysget, mon, Monitor, % A_Index 
	out .= "`nMonitor #" A_Index " coords:`n"
	out .= "Left: " monLeft "`n"
	out .= "Right: " monRight "`n"
	out .= "Top: " monTop "`n"
	out .= "Bottom: " monBottom "`n"
}
clipboard := out
msgbox % out

Return to “Gaming Scripts (v1)”

Who is online

Users browsing this forum: No registered users and 45 guests