[Script] WinHole

Post your working scripts, libraries and tools for AHK v1.1 and older
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

[Script] WinHole

15 Apr 2017, 18:22

Introduction
This is a script for making a see-through hole (circle) in the window under the mouse. The center of the hole follows the mouse, the hole can be inverted.

Preview
For a short video preview, visit sendvid.com. (Makes an inverted hole in a window which shows a cup of coffee, revealing the code for this script beneath, toggles inverted setting.)

Download
winhole.ahk
(3.91 KiB) Downloaded 791 times
How to use
Hotkeys:
  • Esc,exit script. Restores the window first, if needed.
  • F1 Toggle on/off.
  • F2 Toggle inverted setting when the toggle is on.
  • F3 Toggle pause when the toggle is on. When paused, the hole doesn't follow the mouse.
  • WheelUp Increases the radius of the hole
  • WheelDown Decreases the radius of the hole
Optional setup:
At the top of the script, these settings can be changed,
  • radius, the starting radius of the circle.
  • incrementthe amount to decrease/increase radius of circle when turning the scroll wheel.
  • inverted, If false, the region is see-throughable.
  • rate, the period (ms) of the timer.
For changing the shape of the hole, modify region, it should an array where each element is a pair of coordinates which forms a shape with closed boundary, eg, region:=[{x:x0,y:y0},{x:x1,y:y1},...,{x:xn,y:yn},{x:x0,y:y0}], where xk,yk are integers.

Additional regions
Put the functions in the code, and replace two occasions of region:=makeCircle(radius) with region:=x(radius).
A fancy heart
A regular triangle
About the implementaion
The hole is a polygon set by WinSet,Region, x-y....

Known issues and limitations
  • Very limited testing, only tested on 1.1.25.01 Unicode 64, Win7.
  • Tested only with the circle region.
  • Some windows doesn't seem to respond well to WinSet,Region,...
Misc
This was made for fun, if you make a custom shape, please share it, I'll link to it from this post :)
You may use this in any way and any context you like.
Good luck :wave:

Edit: Minor change in the heart code
Last edited by Helgef on 21 Apr 2017, 08:21, edited 2 times in total.
User avatar
tidbit
Posts: 1280
Joined: 29 Sep 2013, 17:15
Location: USA

Re: [Script] WinHole

15 Apr 2017, 18:26

very interesting :idea:
rawr. fear me.
*poke*
Is it December 21, 2012 yet?
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [Script] WinHole

16 Apr 2017, 02:00

tidbit wrote:very interesting :idea:
I actually found a real life application for it, I was going to upload the code for the script, so I had my file explorer open beneath my browser, the script was running so I made a hole in the browser, picked up the file, closed the hole and dropped the file in post editor. :lol:
Here is a custom region for you,

Code: Select all

heart4tidbit(r:=100)
{
	n:=r*4
	n:= n>=997 ? 997 : n			; There is a maximum of 2000 points for WinSet,Region,...
	region:=[]
	oY:=-r//2
	Loop, % n
	{
		x:=-2+4*(A_Index-1)/(n-1)
		y:=-sqrt(1-(abs(x)-1)**2)
		region.push({x:x*r, y:y*r+oY})
	}
	Loop, % n
	{
		x:=2-4*(A_Index-1)/(n-1)
		y:=3*sqrt(1-sqrt(abs(x/2)))
		region.push({x:x*r, y:y*r+oY})
	}
	return region
}
Put in script, and replace (at two places) region:=makeCircle(radius) with region:=heart4tidbit(radius). :thumbup:
hearth4tidbit.png
hearth4tidbit.png (55.17 KiB) Viewed 10083 times
Last edited by Helgef on 21 Apr 2017, 08:20, edited 1 time in total.
just me
Posts: 9763
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [Script] WinHole

16 Apr 2017, 06:18

Hi Helgef,

good job!

If you want to play a bit more with it you might be interested in calling the Regions API directly:

Code: Select all

#NoEnv
W := 400
H := 400
Gui, +hwndHGUI +LastFound -Caption +AlwaysOnTop
Gui, Color, Black
Gui, Show, w%W% h%H%, Test
Points := [{X: W//2, Y: 0}, {X: W, Y: H//2}, {X: W//2, Y: H}, {X: 0, Y: H//2}]
HRGN1 := Rgn_CreatePolygonRgn(Points)
; HRGN1 := Rgn_CreateEllipticRgn(0, 0, W, H)
HRGN2 := Rgn_CreateEllipticRgn(100, 100, W - 100, H - 100)
Rgn_CombineRgn(HRGN, HRGN1, HRGN2, 3)
Rgn_SetWindowRgn(HGUI, HRGN)
OnMessage(0x0201, "GuiMove")
Return
; --------------------------------------------------------------------------------------------------------------------------------
GuiEscape:
ExitApp
; --------------------------------------------------------------------------------------------------------------------------------
GuiMove() {
   PostMessage, 0xA1, 2
}
; ================================================================================================================================
; Regions -> msdn.microsoft.com/en-us/library/dd162913(v=vs.85).aspx
;
; Region Flags (Return Values)
;    ERROR               0
;    NULLREGION          1
;    SIMPLEREGION        2
;    COMPLEXREGION       3
;
; CombineRgn() Styles (Mode)
;    RGN_AND             1
;    RGN_OR              2
;    RGN_XOR             3
;    RGN_DIFF            4
;    RGN_COPY            5
;
; PolyFill() Modes
;    ALTERNATE           1
;    WINDING             2
; ================================================================================================================================
Rgn_CombineRgn(ByRef HRGNC, HRGN1, HRGN2, Mode) {
   HRGN := Rgn_CreateRectRgn(0, 0, 0, 0)
   Result := DllCall("CombineRgn", "Ptr", HRGN, "Ptr", HRGN1, "Ptr", HRGN2, "Int", Mode, "Int")
   HRGNC := Result ? HRGN : 0
   Return Result
}
; ================================================================================================================================
Rgn_CreateEllipticRgn(Left, Top, Right, Bottom) {
   Return DllCall("CreateEllipticRgn", "Int", Left, "Int", Top, "Int", Right, "Int", Bottom, "UPtr")
}
; ================================================================================================================================
Rgn_CreateEllipticRgnIndirect(ByRef RECT) {
   Return DllCall("CreateEllipticRgnIndirect", "Ptr", &RECT, "UPtr")
}
; ================================================================================================================================
Rgn_CreatePolygonRgn(Points, FillMode := 1) {
   If !IsObject(Points) || !(PtCount := Points.Length())
      Return 0
   VarSetCapacity(PtArray, 8 * PtCount, 0)
   Addr := &PtArray
   For Each, Point In Points {
      Addr := NumPut(Point.X, Addr + 0, "Int")
      Addr := NumPut(Point.Y, Addr + 0, "Int")
   }
   Return DllCall("CreatePolygonRgn", "Ptr", &PtArray, "Int", PtCount, "Int", FillMode, "UPtr")
}
; ================================================================================================================================
Rgn_CreateRectRgn(Left, Top, Right, Bottom) {
   Return DllCall("CreateRectRgn", "Int", Left, "Int", Top, "Int", Right, "Int", Bottom, "UPtr")
}
; ================================================================================================================================
Rgn_CreateRectRgnIndirect(ByRef RECT) {
   Return DllCall("CreateRectRgnIndirect", "Ptr", &RECT "UPtr")
}
; ================================================================================================================================
Rgn_CreateRoundRectRgn(Left, Top, Right, Bottom, RX, RY) {
   Return DllCall("CreateRoundRectRgn", "Int", Left, "Int", Top, "Int", Right, "Int", Bottom, "Int", RX, "Int", RY, "UPtr")
}
; ================================================================================================================================
Rgn_GetWindowRgn(HWND, ByRef HRGNW) {
   HRGN := Rgn_CreateRectRgn(0, 0, 0, 0)
   Result := DllCall("GetWindowRgn", "Ptr", HWND, "Ptr", HRGN, "Int")
   HRGNW := Result ? HRGN : 0
   Return Result
}
; ================================================================================================================================
Rgn_GetRgnBox(HRGN, ByRef Left, ByRef Top, ByRef Right, ByRef Bottom) {
   VarSetCapacity(RECT, 16, 0)
   Result := DllCall("GetRgnBox", "Ptr", HRGN, "Ptr", &RECT, "Int")
   Left := NumGet(RECT, 0, "Int"), Top := NumGet(RECT, 4, "Int")
   Right := NumGet(RECT, 8, "Int"), Bottom := NumGet(RECT, 12, "Int")
   Return Result
}
; ================================================================================================================================
Rgn_SetWindowRgn(HWND, HRGN, Redraw := True) {
   Return DllCall("SetWindowRgn", "Ptr", HWND, "Ptr", HRGN, "UInt", !!Redraw, "Int")
}
; ================================================================================================================================
Rgn_DeleteRgn(HRGN) {
   Return DllCall("DeleteObject", "Ptr", HRGN, "UInt")
}
; ================================================================================================================================
If you're interested you could complete the wrapper functions.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [Script] WinHole

16 Apr 2017, 09:56

Hi just me :mrgreen:
I took a quick look at your code, that seems much easier to work with. Nice one. :thumbup:
User avatar
noname
Posts: 516
Joined: 19 Nov 2013, 09:15

Re: [Script] WinHole

17 Apr 2017, 01:25

I actually found a real life application for it
I was trying it when recording with audacity a youtube music video to get a look at the levels I could simply punch a hole in the fullscreen chrome window.
Win10 has some quirks when resizing ,this will be a quick shortcut.

The 2000 points limit looked overkill but seeing the circle code ........... :idea:

Thanks for annotating the code !
User avatar
Drugwash
Posts: 853
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: [Script] WinHole

20 Apr 2017, 06:29

Funny toy! :)
I'd upgrade it with an alternate option to show the entire window that's currently under cursor beneath the topmost window.
In example, if there is a full screen browser and a small Notepad window beneath it, activating the script would show the entire Notepad window as long as the cursor hovers within its boundaries. Maybe skip Desktop (or not).
A 'temporary' hotkey might come in handy too, in addition to the toggle - only show the hole while hotkey is kept pressed, close it when released.
Part of my AHK work can be found here.
User avatar
hoppfrosch
Posts: 449
Joined: 07 Oct 2013, 04:05
Location: Rhine-Maine-Area, Hesse, Germany
Contact:

Re: [Script] WinHole

21 Apr 2017, 00:03

Just remembering the good ole times: Shimanov once build a donut shaped window .... tasty!
User avatar
Coderooney
Posts: 46
Joined: 23 Mar 2017, 22:41

Re: [Script] WinHole

21 Apr 2017, 01:08

Hehehe this is really cool!! For practical uses, you could even set up one of those Cardan grille codes:

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

Re: [Script] WinHole

21 Apr 2017, 08:28

I'm glad you found it useful/funny/nostaligic/inspiring. :lol:

I've been thinking on some of the possibilites to cut windows for useful purposes, I'll probably won't bother with it much more though, but if I would, I'd use the functions by just me, just above.

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

Re: [Script] WinHole

22 Apr 2017, 04:26

SwissWin
This was done for experimental purposes, and requires the rgn_ functions a few post up, by just me.
SwissWin(state,mode:="swiss",inv:=false)
  • state, "on" or "off"
  • mode, "swiss" for cutting all controls, or "ctrl" for cutting one control.
  • inv, false or true for inverting the cut.
Hotkey descriptions:
  • F1, cuts out the non-control area of the window under the mouse.
  • F2, invert F1.
  • F3, cuts out all but the control under the mouse
  • F4, invert F2
  • F5, restore.
  • ESC, restore and exit.

Some windows have some control covering the whole window, in those cases the effect isn't really seen or hides the whole window.

Code: Select all

gui,add,edit,w100	; A window for testing.
gui,add,text,,hi
gui,add,listview,,a|b|c
gui,add,button,gesc,Close
gui,show,w400 h300
F1::SwissWin("on")
F2::SwissWin("on",,true)
F3::SwissWin("on","ctrl")
F4::SwissWin("on","ctrl",true)
F5::SwissWin("off")
esc::
guiclose:
	SwissWin("off")
	exitapp
return
SwissWin(state,mode:="swiss",inv:=false){
	static hwnd:="", hCtrl:=""
	static rx:=5,ry:=5
	if (state="off") {
		if hwnd
			Rgn_SetWindowRgn(hwnd,0)
		hwnd:="",hCtrl:=""
		return
	} else if hwnd {
		SwissWin("off")
	}
	MouseGetPos,,, hwnd,hCtrl,2
	WinGetPos,,, ww, wh, % "ahk_id " hwnd
	rgnWin:=Rgn_CreateRectRgn(0, 0, ww, wh)
	
	if (mode="swiss") {
		WinGet, ctrls, ControlListHwnd , % "ahk_id " hwnd
		for k, hC in StrSplit(ctrls,"`n"){
			ControlGetPos, cx, cy, cw, ch,, % "ahk_id" hC
			rgnCtrl:=Rgn_CreateRoundRectRgn(cx, cy, cx+cw, cy+ch, rx, ry)
			if prgn
				Rgn_CombineRgn(prgn,prgn,rgnCtrl,2)
			else
				prgn:=rgnCtrl
		}
		if inv
			Rgn_CombineRgn(prgn,rgnWin,prgn,4)
	} else if (mode="ctrl") {
		ControlGetPos, cx, cy, cw, ch,, % "ahk_id" hCtrl
		prgn:=Rgn_CreateRoundRectRgn(cx, cy, cx+cw, cy+ch, rx, ry)
		if inv
			Rgn_CombineRgn(prgn,rgnWin,prgn,4)
	}
	Rgn_SetWindowRgn(hwnd, prgn)
	return
}
Good luck.
Edit:
Drugwash wrote:Typo in the code: guiecape: --> guiescape:
Ty, fixed.
Last edited by Helgef on 22 Apr 2017, 05:29, edited 1 time in total.
User avatar
Drugwash
Posts: 853
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: [Script] WinHole

22 Apr 2017, 05:00

Typo in the code: guiecape: --> guiescape:
Part of my AHK work can be found here.
20170201225639
Posts: 144
Joined: 01 Feb 2017, 22:57

Re: [Script] WinHole

22 Apr 2017, 10:03

thanks for the nice utility.



here's a reasonably faithful reenactment of a recent situation where i used winhole to peek at a (auto-refresh) file that lists of the current content of important global arrays
https://my.mixtape.moe/kmpnfe.webm




a user experience observation: i find that i use this much more when i configure it so that the hole is created when some key is pressed down and destoryed upon keyup (as opposed to toggle on/off)

as in:

Code: Select all

#h::
	run  winhole.ahk   ; file is modified so hole is created in auto-execute section
	Keywait h
	Send {ESC}
        return
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [Script] WinHole

22 Apr 2017, 12:01

@ A_Now :)
I'm glad you found it useful, I like your idea with the run,winhole.ahk hotkey. If you add

Code: Select all

#SingleInstance, off
at the top of winhole.ahk, and eg,

Code: Select all

; create the hole here, in the autoexecute section
keywait, esc, d
exit()
and finally, add

Code: Select all

#MaxThreadsPerHotkey,5 
to your run,... script, then you can keep punshing holes through the windows beneath, by applying your run,... hotkey, then hit esc to close all holes. :lol:
20170201225639
Posts: 144
Joined: 01 Feb 2017, 22:57

Re: [Script] WinHole

24 Apr 2017, 14:08

this is awesome. thanks for sharing this tip!
when i posted the above i actually didn't realize that you can *activate* the window you see through the hole and select text etc (that is, activate it without destroying the hole). it's even more useful than i thought!
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: [Script] WinHole

29 Mar 2019, 09:36

Wow, I was trying to understand WinSet Regio better and fell on this.

This is genious stuff. Thanks Helgef and just me
User avatar
Tigerlily
Posts: 377
Joined: 04 Oct 2018, 22:31

Re: [Script] WinHole

31 Mar 2019, 02:04

This is super cool Helgef. A Hole lot of fun :D
-TL
seabirdr
Posts: 10
Joined: 04 Aug 2014, 10:19

Re: [Script] WinHole

01 May 2024, 07:32

Dragging files from Explorer to other programs used to be such a pain, but with your script (and a couple of tiny tweaks), it's now a breeze! 😄 You've saved me so much time and frustration, and I can't express how grateful I am!
veri42
Posts: 2
Joined: 18 Jun 2024, 03:36

Re: [Script] WinHole

10 Oct 2024, 05:41

This script works great! However, I have a small issue. After triggering F1 (for example, in VSCode), when I switch to another window (such as Chrome to select and copy something), returning to VSCode causes it to lose focus...
gongnl
Posts: 98
Joined: 05 Jan 2015, 03:57
Location: /gongnltmp/

Re: [Script] WinHole

17 Oct 2024, 03:22

This script works great. I hope an expert can upgrade this script to V2 and add the functionality of switching between windows by holding down shift key and turning scroll wheel. Additionally, I added C hotkey for copying。

Code: Select all

 F3::timer((pause:=!pause)?-1:1) 
c::           ; When on, type c for copying. 
   Send, ^c sleep, 100 
   timer(toggle:=!toggle,region,inverted,rate),pause:=0 
  return
WheelUp::  

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: submeg and 115 guests