iPhilip and transparent click through windows Topic is solved

Get help with using AutoHotkey and its commands and hotkeys
HenriAug
Posts: 11
Joined: 10 May 2017, 18:16

iPhilip and transparent click through windows

23 Aug 2017, 18:39

Hi.

I want to draw some lines on the screen in a way that it does not affect what the user can click. The idea is to create some metrics on the screen, similar to MB Ruler.

I tried using iPhilip's draw functions. I've managed to draw some lines on the screen with success and i can click through them but when i use win+D to show desktop and then click an explorer window the window with the lines gets all white again.

Code: Select all

;https://autohotkey.com/board/topic/29449-gdi-standard-library-145-by-tic/

; DrawFunctions.ahk
;
; by iPhilip
; November 15, 2011
;
; Inspired by the work of Shimanov, Metaxal, maximo3491, Relayer
; Reference: http://www.autohotkey.com/forum/topic41756.html
;
; Defines a set of functions to draw color dots, lines, and boxes on the screen
;
; init_draw(c=1)
;      Moves the mouse off the screen and blocks any further input.
;      Initializes buffers and paints the canvas with color index c (default = 1 = black).
;      See below for the index/color map. A value of 0 makes the canvas appear transparent.
;
; exit_draw()
;      Launches when the left mouse button is clicked, restoring the mouse to its original coordinates
;      and exiting the application.
;
; paint_canvas(c=1)
;      Paints the canvas with color index c (default = 1 = black). See below for the index/color map.
;      A value of 0 makes the canvas appear to be transparent. It's actually a screenshot of the background.
;      The canvas gets erased each time this function is called.
;
; draw_dot(x, y, r=1, c=16)
;      Draws a dot of radius r pixels and color index c at (x,y). The default radius is 1.
;      The default color index is 16 (white). See below for the index/color map.
;
; draw_line(x0, y0, x1, y1, w=1, c=16)
;      Draws a line of width 2w pixels and color index c from (x0,y0) to (x1,y1). The line has rounded ends.
;      The default width is 1. The default color index is 16 (white). See below for the index/color map.
;
; draw_box(x0, y0, x1, y1, c=16)
;      Draws a box defined by the upper-left coordinates (x0,y0) and the bottom-right coordinates (x1,y1)
;      with color index c. The default color index is 16 (white). See below for the index/color map.
;
; Gloval variables: origX, origY, hdc_buffer1, hdc_buffer2, hdc_canvas, color[0-16]
;
;---------------------------------------------------------------------------------------------------------

init_draw(c=1) {
   global origX, origY, hdc_buffer1, hdc_buffer2, hdc_canvas, color0

   ; Move the mouse off the screen and block any further input
   CoordMode, Mouse, Screen
   MouseGetPos origX, origY
   ;MouseMove A_ScreenWidth, A_ScreenHeight, 0
   ;BlockInput MouseMove

   ; Create a working buffer
   hdc_screen  := DllCall("GetDC", "uint", 0)
   hdc_buffer1 := DllCall("CreateCompatibleDC", "uint", hdc_screen)
   hbm_buffer1 := DllCall("CreateCompatibleBitmap", "uint", hdc_screen, "int", A_ScreenWidth, "int", A_ScreenHeight)
   DllCall("SelectObject", "uint", hdc_buffer1, "uint", hbm_buffer1)

   ; Create a secondary buffer
   hdc_buffer2 := DllCall("CreateCompatibleDC", "uint", hdc_screen)
   hbm_buffer2 := DllCall("CreateCompatibleBitmap", "uint", hdc_screen, "int", A_ScreenWidth, "int", A_ScreenHeight)
   DllCall("SelectObject", "uint", hdc_buffer2, "uint", hbm_buffer2)

   ; Initialize the buffers with a screenshot so that the canvas appears transparent
   DllCall("BitBlt", "uint", hdc_buffer1, "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_screen, "int", 0, "int", 0, "uint", 0x00CC0020)
   DllCall("BitBlt", "uint", hdc_buffer2, "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_screen, "int", 0, "int", 0, "uint", 0x00CC0020)
   ; Create a window with the size of the display
   
   ;THOSE TWO ARE THE TWO ORIGINAL LINES
   ;Gui, +AlwaysOnTop -Caption  
   ;Gui, Show, x0 y0 w%A_ScreenWidth% h%A_ScreenHeight%


   Gui, CanvasGUI:New, +AlwaysOnTop -Caption +Owner +LastFound +E0x20, CanvasGUITitle
   Gui, CanvasGUI:Show, NoActivate x0 y0 w%A_ScreenWidth% h%A_ScreenHeight%
   WinSet, TransColor, White 255, CanvasGUI

   ; Get the handle of the window associated with the canvas
   PID := DllCall("GetCurrentProcessId")
   WinGet, hw_canvas, ID, ahk_class AutoHotkeyGUI ahk_pid %PID%
   hdc_canvas := DllCall("GetDC", "uint", hw_canvas)

   ; Define color array
   ; References: http://en.wikipedia.org/wiki/Web_colors#HTML_color_names
   ;             http://www.autohotkey.com/forum/topic47746.html
   color_codes = 0x000000   ; 1.  Black
                ,0x000080   ; 2.  Navy
                ,0x008000   ; 3.  Green
                ,0x008080   ; 4.  Teal
                ,0x800000   ; 5.  Maroon
                ,0x800080   ; 6.  Purple
                ,0x808000   ; 7.  Olive
                ,0xC0C0C0   ; 8.  Silver
                ,0x808080   ; 9.  Gray
                ,0x0000FF   ; 10. Blue
                ,0x00FF00   ; 11. Lime
                ,0x00FFFF   ; 12. Aqua
                ,0xFF0000   ; 13. Red
                ,0xFF00FF   ; 14. Fuchsia
                ,0xFFFF00   ; 15. Yellow
                ,0xFFFFFF   ; 16. White
   StringSplit color, color_codes, `,
   Loop 16
      color%A_Index% := SubStr(color%A_Index%,1,2) SubStr(color%A_Index%,7,2) SubStr(color%A_Index%,5,2) SubStr(color%A_Index%,3,2)

   ; Paint the canvas with the initial color
   paint_canvas(c)

   ; Define the exit function that gets called when the mouse is clicked
   ; Reference: http://www.autohotkey.com/docs/commands/OnMessage.htm
   ;WM_LBUTTONDOWN = 0x201
   ;OnMessage(WM_LBUTTONDOWN, "exit_draw")
}

exit_draw() {
   global origX, origY
   ;BlockInput MouseMoveOff
   MouseMove origX, origY, 0
   ;ExitApp
}

paint_canvas(c=1) {   ; Default canvas color is black
   global hdc_buffer1, hdc_buffer2, hdc_canvas, color0
   if !c   ; 0 = transparent
   {
      DllCall("BitBlt", "uint", hdc_buffer2, "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_buffer1, "int", 0, "int", 0, "uint", 0x00CC0020)
      DllCall("BitBlt", "uint", hdc_canvas , "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_buffer2, "int", 0, "int", 0, "uint", 0x00CC0020)
      return
   }
   ;MsgBox, % "painting canvas"
   cBrush := DllCall("gdi32.dll\CreateSolidBrush", "uint", color%c%)
   DllCall("SelectObject", "uint", hdc_buffer2, "uint", cBrush)
   DllCall("BitBlt", "uint", hdc_buffer2, "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_buffer1, "int", 0, "int", 0, "uint", 0x00F00021)
   DllCall("SelectObject", "uint", hdc_buffer2, "uint", 0)
   DllCall("gdi32.dll\DeleteObject", "uint", cBrush)
   DllCall("BitBlt", "uint", hdc_canvas , "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_buffer2, "int", 0, "int", 0, "uint", 0x00CC0020)
}

draw_dot(x, y, r=1, c=16) {
   global hdc_buffer2, hdc_canvas, color0
   cBrush  := DllCall("gdi32.dll\CreateSolidBrush", "uint", color%c%)
   cRegion := DllCall("gdi32.dll\CreateRoundRectRgn", "int", x-r, "int", y-r, "int", x+r, "int", y+r, "int", r*2, "int", r*2)
   DllCall("gdi32.dll\FillRgn" , "uint", hdc_buffer2 , "uint", cRegion , "uint", cBrush)
   DllCall("gdi32.dll\DeleteObject", "uint", cRegion)
   DllCall("gdi32.dll\DeleteObject", "uint", cBrush)
   DllCall("BitBlt", "uint", hdc_canvas , "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_buffer2, "int", 0, "int", 0, "uint", 0x00CC0020)
}

draw_line(x0, y0, x1, y1, w=1, c=16) {
   global hdc_buffer2, hdc_canvas, color0
   dx := x1 - x0
   dy := y1 - y0
   dxy := abs(dx) > abs(dy) ? abs(dx) : abs(dy)
   dx := dx / dxy
   dy := dy / dxy
   cBrush := DllCall("gdi32.dll\CreateSolidBrush", "uint", color%c%)
   Loop % round(dxy) + 1
   {
      cRegion := DllCall("gdi32.dll\CreateRoundRectRgn", "int", x0-w, "int", y0-w, "int", x0+w, "int", y0+w, "int", w*2, "int", w*2)
      DllCall("gdi32.dll\FillRgn" , "uint", hdc_buffer2 , "uint", cRegion , "uint", cBrush)
      DllCall("gdi32.dll\DeleteObject", "uint", cRegion)
      x0 += dx
      y0 += dy
   }
   DllCall("gdi32.dll\DeleteObject", "uint", cBrush)
   DllCall("BitBlt", "uint", hdc_canvas , "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_buffer2, "int", 0, "int", 0, "uint", 0x00CC0020)
}

draw_box(x0, y0, x1, y1, c=16) {
   global hdc_buffer2, hdc_canvas, color0
   cBrush  := DllCall("gdi32.dll\CreateSolidBrush", "uint", color%c%)
   cRegion := DllCall("gdi32.dll\CreateRectRgn", "int", x0, "int", y0, "int", x1, "int", y1)
   DllCall("gdi32.dll\FillRgn" , "uint", hdc_buffer2 , "uint", cRegion , "uint", cBrush)
   DllCall("gdi32.dll\DeleteObject", "uint", cRegion)
   DllCall("gdi32.dll\DeleteObject", "uint", cBrush)
   DllCall("BitBlt", "uint", hdc_canvas , "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_buffer2, "int", 0, "int", 0, "uint", 0x00CC0020)
}
Here is the hotkey i've used

Code: Select all

+^!q::
    init_draw(16)
    draw_line(A_ScreenWidth/3,0,A_ScreenWidth/3,A_ScreenHeight,5,1)
    draw_line(2*A_ScreenWidth/3,0,2*A_ScreenWidth/3,A_ScreenHeight,5,1)
    draw_line(0,A_ScreenHeight/3,A_ScreenWidth,A_ScreenHeight/3,5,1)
    draw_line(0,2*A_ScreenHeight/3,A_ScreenWidth,2*A_ScreenHeight/3,5,1)
return
(Notice that i've modified it a little bit so it doesn't block user input)

Here is a link to a gif of that behavior.

Please, anybody knows how to fix it?
Here is a link to a .gif showing the problem, hosted in my dropbox
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: iPhilip and transparent click through windows

23 Aug 2017, 19:24

Your posted code does not produce a "window with the lines" for me, and I don't have the problem. Your script is fine!!
Where do you create the problematic GUI?
HenriAug
Posts: 11
Joined: 10 May 2017, 18:16

Re: iPhilip and transparent click through windows

23 Aug 2017, 20:27

Hmm, strange. You've used the hotkey to trigger the draw_line functions? It did anything for you?

Code: Select all

+^!q::
    init_draw(16)
    draw_line(A_ScreenWidth/3,0,A_ScreenWidth/3,A_ScreenHeight,5,1)
    draw_line(2*A_ScreenWidth/3,0,2*A_ScreenWidth/3,A_ScreenHeight,5,1)
    draw_line(0,A_ScreenHeight/3,A_ScreenWidth,A_ScreenHeight/3,5,1)
    draw_line(0,2*A_ScreenHeight/3,A_ScreenWidth,2*A_ScreenHeight/3,5,1)
return
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: iPhilip and transparent click through windows

23 Aug 2017, 20:37

Yes, I used Shift+Ctrl+Alt+Q (all modifiers were the Left version) and I saw a grid consisting of thick black lines dividing my screen (one monitor, 1920x1080) into 3x3 equal regions.
I used the two scripts you posted, hotkeys were last, I altered nothing. And I see no taskbar button for a AHK Gui, and I have no problem like you show in you gif.
Are you certain that you have no more includes that would mess up things? Where is the GUI created?

I don't want to come across as being mean, I really wonder there must be more code .. somewhere ??

For extreme clarity (I just re-read my post): I see the Grid, I don't see the AHK Gui taskbar button down below.
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: iPhilip and transparent click through windows

23 Aug 2017, 21:14

Sorry, I looked again at your gif, you don't have a taskbar button either.
You seem to activate the window via Alt+Tab. I tested again with Alt+Tab.

I still can not reproduce the behaviour you show. I apologize for the confusion.
HenriAug
Posts: 11
Joined: 10 May 2017, 18:16

Re: iPhilip and transparent click through windows

23 Aug 2017, 21:27

Indeed the taskbar icon is intended to not appear and the code divides your screen in 9 rectangles. This part is correct.

I showed the alt+tab just so you can see by the miniature that the window is now fully white. I didn't show with alt+tab previously but it was, as expected, transparent with the black lines.

The thing is: everytime i see my desktop and then open any other window the screen turns white. As you can see everything works normally. I can switch windows and it still works. Then i see my desktop and open some window and the autohotkey window gets all white.

*I just occured to me that it that happens with somebody else you hsould probably have an shortcut for restarting your app

Code: Select all

F5::
    Reload
return
This way if the white screen pops and cover the screen you can hit F5 to reload the app and it's gone. (Or alt+tab to the autohotkey window and press Alt+F4).

Note the script still creates an autohotkey window and you can still access it with alt+tab. But the WinSet, Transparent makes you able to click through it.

Also i've noticed that the init_draw(16) method paints it all white AFTER setting it's transparency with WinSet. But it made no difference when I tried using WinSet after the paint_canvas(c) method:

Code: Select all

   paint_canvas(c)
   WinSet, TransColor, White 255, CanvasGUI
EDIT: this behavior also happens even when i don't use a transparent window. So, for example calling init_draw(15) (yellow) instead of init_draw(16) (white) doesn't fix it. So after going to desktop and then back the window turns all white.
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: iPhilip and transparent click through windows

23 Aug 2017, 22:09

To answer my own question: the Gui is created inside init_draw() with the title CanvasGUITitle.
I have no explanation what happened earlier. Maybe I was having a stroke. :oops:

We can hide the Gui with

Code: Select all

F5:: Gui, CanvasGUI: Hide
No need to reload if you want to avoid it.

I have still not seen a white screen after playing with it some more.
I'm on Win10 64 bit and I use AHK v1.1.26.01 64 bit to run the script.

Edit: withinit_draw(15) i use WinSet, TransColor, yellow 255, CanvasGUI and no problems.
Edit 2: do you need the 255 inside the WinSet command? I removed it for testing and it does not make a difference for me.
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: iPhilip and transparent click through windows

23 Aug 2017, 22:20

I can now reproduce the error: I have to click the rightmost edge on the taskbar (which also shows the desktop). even with yellow, I see a white screen.
HenriAug
Posts: 11
Joined: 10 May 2017, 18:16

Re: iPhilip and transparent click through windows

23 Aug 2017, 22:25

wolf_II wrote:To answer my own question: the Gui is created inside init_draw() with the title CanvasGUITitle.
Sorry for not answering it. I thought you had it after your second post.

I don't need the 255 exactly but later i'm gonna add an option for changing the opacity so i left it there to remind where should i put the transparency argument.

I'm on a Win 7 64 bit but i have a hunch that this is not the problem... honsetly i'm new to all that DllCall and windows API and stuff so i don't see anything wrong yet.
I can now reproduce the error: I have to click the rightmost edge on the taskbar (which also shows the desktop). even with yellow, I see a white screen.
hmmm so it's very likely not a bug on our computer but rather something on the code...
obeeb
Posts: 140
Joined: 20 Feb 2014, 19:15

Re: iPhilip and transparent click through windows

23 Aug 2017, 22:33

Happens to me every time on my windows 7.
Start the script -> ^#!q -> #d -> Switch to any program and I immediately get a white window.
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: iPhilip and transparent click through windows

23 Aug 2017, 22:34

@ HenriAug:
There is a difference between one desktop that you see normally and the desktop you see with clicking the bottom right corner:
Try this:

Code: Select all

#Persistent
SetTimer, Timer

Timer:
    WinGetClass, out, A
    ToolTip, %out%
Return
This shows me the class of the active window. Normal desktop is "Progman" the other is "WorkerW".
I have the feeling this has some significance to the problem.

@ obeeb: does that ring a bell with you?
HenriAug
Posts: 11
Joined: 10 May 2017, 18:16

Re: iPhilip and transparent click through windows

23 Aug 2017, 22:53

obeeb wrote:Happens to me every time on my windows 7.
Start the script -> ^#!q -> #d -> Switch to any program and I immediately get a white window.
Thanks for testing.
This shows me the class of the active window. Normal desktop is "Progman" the other is "WorkerW".
Indeed. If i minimize everything it will display "tooltips_class32". Then i click the desktop and it's Progman. But if i use win+D or click right bottom it's "WorkerW". Same as you.

Maybe when you use WorkerW something changes in the memory and some pointer gets pointed to the wrong location. IDK. I'm testing variables to see their value before and after the window gets white

Code: Select all

+q::
    MsgBox, , Test, % "hdc_canvas = " . hdc_canvas . "`nhdc_buffer1 = " . hdc_buffer1 . "`nhdc_buffer2 = " . hdc_buffer2
return
They're still the same before and after the white screenn

edit: what is intriguing me is that there is no code that is run when on any event regarding the desktop or something...

EDIT2: i've found out that Redrawing the window causes it to go white

Code: Select all

	WinSet, Redraw, , CanvasGUI
obeeb
Posts: 140
Joined: 20 Feb 2014, 19:15

Re: iPhilip and transparent click through windows  Topic is solved

24 Aug 2017, 18:34

wolf_II wrote:This shows me the class of the active window. Normal desktop is "Progman" the other is "WorkerW".
I have the feeling this has some significance to the problem.
@ obeeb: does that ring a bell with you?
This is related to what's described here: https://blogs.msdn.microsoft.com/oldnew ... 0/?p=39153 I have a vague recollection of already reading this blog post.
Microsoft were not capable of simply minimizing and hiding all the windows in order to show the desktop so they created an additional window which is usually hidden and is the "real" desktop and when you do "show desktop" they bring it to the top.

This causes CanvasGUI to be repainted and it repaints without the changes that were done with GDI.
I did some refactoring(paint_canvas is not called from init_draw anymore), added WM_PAINT message handling that redoes the GDI changes and now it works.

Code: Select all

+^!q::
	init_draw()
repaint:
	paint_canvas(16)
	draw_line(A_ScreenWidth/3,0,A_ScreenWidth/3,A_ScreenHeight,5,1)
	draw_line(2*A_ScreenWidth/3,0,2*A_ScreenWidth/3,A_ScreenHeight,5,1)
	draw_line(0,A_ScreenHeight/3,A_ScreenWidth,A_ScreenHeight/3,5,1)
	draw_line(0,2*A_ScreenHeight/3,A_ScreenWidth,2*A_ScreenHeight/3,5,1)
return

;https://autohotkey.com/board/topic/29449-gdi-standard-library-145-by-tic/

; DrawFunctions.ahk
;
; by iPhilip
; November 15, 2011
;
; Inspired by the work of Shimanov, Metaxal, maximo3491, Relayer
; Reference: http://www.autohotkey.com/forum/topic41756.html
;
; Defines a set of functions to draw color dots, lines, and boxes on the screen
;
; init_draw(c=1)
;      Moves the mouse off the screen and blocks any further input.
;      Initializes buffers and paints the canvas with color index c (default = 1 = black).
;      See below for the index/color map. A value of 0 makes the canvas appear transparent.
;
; exit_draw()
;      Launches when the left mouse button is clicked, restoring the mouse to its original coordinates
;      and exiting the application.
;
; paint_canvas(c=1)
;      Paints the canvas with color index c (default = 1 = black). See below for the index/color map.
;      A value of 0 makes the canvas appear to be transparent. It's actually a screenshot of the background.
;      The canvas gets erased each time this function is called.
;
; draw_dot(x, y, r=1, c=16)
;      Draws a dot of radius r pixels and color index c at (x,y). The default radius is 1.
;      The default color index is 16 (white). See below for the index/color map.
;
; draw_line(x0, y0, x1, y1, w=1, c=16)
;      Draws a line of width 2w pixels and color index c from (x0,y0) to (x1,y1). The line has rounded ends.
;      The default width is 1. The default color index is 16 (white). See below for the index/color map.
;
; draw_box(x0, y0, x1, y1, c=16)
;      Draws a box defined by the upper-left coordinates (x0,y0) and the bottom-right coordinates (x1,y1)
;      with color index c. The default color index is 16 (white). See below for the index/color map.
;
; Gloval variables: origX, origY, hdc_buffer1, hdc_buffer2, hdc_canvas, color[0-16]
;
;---------------------------------------------------------------------------------------------------------

init_draw() {
   global origX, origY, hdc_buffer1, hdc_buffer2, hdc_canvas, color0

   ; Move the mouse off the screen and block any further input
   CoordMode, Mouse, Screen
   MouseGetPos origX, origY
   ;MouseMove A_ScreenWidth, A_ScreenHeight, 0
   ;BlockInput MouseMove

   ; Create a working buffer
   hdc_screen  := DllCall("GetDC", "uint", 0)
   hdc_buffer1 := DllCall("CreateCompatibleDC", "uint", hdc_screen)
   hbm_buffer1 := DllCall("CreateCompatibleBitmap", "uint", hdc_screen, "int", A_ScreenWidth, "int", A_ScreenHeight)
   DllCall("SelectObject", "uint", hdc_buffer1, "uint", hbm_buffer1)

   ; Create a secondary buffer
   hdc_buffer2 := DllCall("CreateCompatibleDC", "uint", hdc_screen)
   hbm_buffer2 := DllCall("CreateCompatibleBitmap", "uint", hdc_screen, "int", A_ScreenWidth, "int", A_ScreenHeight)
   DllCall("SelectObject", "uint", hdc_buffer2, "uint", hbm_buffer2)

   ; Initialize the buffers with a screenshot so that the canvas appears transparent
   DllCall("BitBlt", "uint", hdc_buffer1, "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_screen, "int", 0, "int", 0, "uint", 0x00CC0020)
   DllCall("BitBlt", "uint", hdc_buffer2, "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_screen, "int", 0, "int", 0, "uint", 0x00CC0020)
   ; Create a window with the size of the display
   
   ;THOSE TWO ARE THE TWO ORIGINAL LINES
   ;Gui, +AlwaysOnTop -Caption  
   ;Gui, Show, x0 y0 w%A_ScreenWidth% h%A_ScreenHeight%


   Gui, CanvasGUI:New, +AlwaysOnTop -Caption +Owner +LastFound +E0x20, CanvasGUITitle
   Gui, CanvasGUI:Show, NoActivate x0 y0 w%A_ScreenWidth% h%A_ScreenHeight%
   WinSet, TransColor, White 255, CanvasGUI

   ; Get the handle of the window associated with the canvas
   PID := DllCall("GetCurrentProcessId")
   WinGet, hw_canvas, ID, ahk_class AutoHotkeyGUI ahk_pid %PID%
   hdc_canvas := DllCall("GetDC", "uint", hw_canvas)

   ; Define color array
   ; References: http://en.wikipedia.org/wiki/Web_colors#HTML_color_names
   ;             http://www.autohotkey.com/forum/topic47746.html
   color_codes = 0x000000   ; 1.  Black
                ,0x000080   ; 2.  Navy
                ,0x008000   ; 3.  Green
                ,0x008080   ; 4.  Teal
                ,0x800000   ; 5.  Maroon
                ,0x800080   ; 6.  Purple
                ,0x808000   ; 7.  Olive
                ,0xC0C0C0   ; 8.  Silver
                ,0x808080   ; 9.  Gray
                ,0x0000FF   ; 10. Blue
                ,0x00FF00   ; 11. Lime
                ,0x00FFFF   ; 12. Aqua
                ,0xFF0000   ; 13. Red
                ,0xFF00FF   ; 14. Fuchsia
                ,0xFFFF00   ; 15. Yellow
                ,0xFFFFFF   ; 16. White
   StringSplit color, color_codes, `,
   Loop 16
      color%A_Index% := SubStr(color%A_Index%,1,2) SubStr(color%A_Index%,7,2) SubStr(color%A_Index%,5,2) SubStr(color%A_Index%,3,2)

   WM_PAINT = 15
   OnMessage(WM_PAINT, "repaint")
}

repaint() {
	gosub repaint
	return 0
}

paint_canvas(c=1) {   ; Default canvas color is black
   global hdc_buffer1, hdc_buffer2, hdc_canvas, color0
   if !c   ; 0 = transparent
   {
      DllCall("BitBlt", "uint", hdc_buffer2, "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_buffer1, "int", 0, "int", 0, "uint", 0x00CC0020)
      DllCall("BitBlt", "uint", hdc_canvas , "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_buffer2, "int", 0, "int", 0, "uint", 0x00CC0020)
      return
   }
   ;MsgBox, % "painting canvas"
   cBrush := DllCall("gdi32.dll\CreateSolidBrush", "uint", color%c%)
   DllCall("SelectObject", "uint", hdc_buffer2, "uint", cBrush)
   DllCall("BitBlt", "uint", hdc_buffer2, "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_buffer1, "int", 0, "int", 0, "uint", 0x00F00021)
   DllCall("SelectObject", "uint", hdc_buffer2, "uint", 0)
   DllCall("gdi32.dll\DeleteObject", "uint", cBrush)
   DllCall("BitBlt", "uint", hdc_canvas , "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_buffer2, "int", 0, "int", 0, "uint", 0x00CC0020)
}

draw_dot(x, y, r=1, c=16) {
   global hdc_buffer2, hdc_canvas, color0
   cBrush  := DllCall("gdi32.dll\CreateSolidBrush", "uint", color%c%)
   cRegion := DllCall("gdi32.dll\CreateRoundRectRgn", "int", x-r, "int", y-r, "int", x+r, "int", y+r, "int", r*2, "int", r*2)
   DllCall("gdi32.dll\FillRgn" , "uint", hdc_buffer2 , "uint", cRegion , "uint", cBrush)
   DllCall("gdi32.dll\DeleteObject", "uint", cRegion)
   DllCall("gdi32.dll\DeleteObject", "uint", cBrush)
   DllCall("BitBlt", "uint", hdc_canvas , "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_buffer2, "int", 0, "int", 0, "uint", 0x00CC0020)
}

draw_line(x0, y0, x1, y1, w=1, c=16) {
   global hdc_buffer2, hdc_canvas, color0
   dx := x1 - x0
   dy := y1 - y0
   dxy := abs(dx) > abs(dy) ? abs(dx) : abs(dy)
   dx := dx / dxy
   dy := dy / dxy
   cBrush := DllCall("gdi32.dll\CreateSolidBrush", "uint", color%c%)
   Loop % round(dxy) + 1
   {
      cRegion := DllCall("gdi32.dll\CreateRoundRectRgn", "int", x0-w, "int", y0-w, "int", x0+w, "int", y0+w, "int", w*2, "int", w*2)
      DllCall("gdi32.dll\FillRgn" , "uint", hdc_buffer2 , "uint", cRegion , "uint", cBrush)
      DllCall("gdi32.dll\DeleteObject", "uint", cRegion)
      x0 += dx
      y0 += dy
   }
   DllCall("gdi32.dll\DeleteObject", "uint", cBrush)
   DllCall("BitBlt", "uint", hdc_canvas , "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_buffer2, "int", 0, "int", 0, "uint", 0x00CC0020)
}

draw_box(x0, y0, x1, y1, c=16) {
   global hdc_buffer2, hdc_canvas, color0
   cBrush  := DllCall("gdi32.dll\CreateSolidBrush", "uint", color%c%)
   cRegion := DllCall("gdi32.dll\CreateRectRgn", "int", x0, "int", y0, "int", x1, "int", y1)
   DllCall("gdi32.dll\FillRgn" , "uint", hdc_buffer2 , "uint", cRegion , "uint", cBrush)
   DllCall("gdi32.dll\DeleteObject", "uint", cRegion)
   DllCall("gdi32.dll\DeleteObject", "uint", cBrush)
   DllCall("BitBlt", "uint", hdc_canvas , "int", 0, "int", 0, "int", A_ScreenWidth, "int", A_ScreenHeight, "uint", hdc_buffer2, "int", 0, "int", 0, "uint", 0x00CC0020)
}
HenriAug
Posts: 11
Joined: 10 May 2017, 18:16

Re: iPhilip and transparent click through windows

25 Aug 2017, 23:08

Touché.

I'm still going through all that windows API and stuff and it's all starting to make sense.
I wonder if i can create a class that automates that stuff. You extend a base class, implement is draw() method and it takes care of that OnMessage and WM_PAINT and stuff. Probably going to make things easier when creating multiple windows.

Thanks a lot obeeb and wolf_II !
obeeb
Posts: 140
Joined: 20 Feb 2014, 19:15

Re: iPhilip and transparent click through windows

26 Aug 2017, 13:07

HenriAug wrote:Touché.
It turned out to be something simple, doesn't mean that it was easy to solve ;-). This behavior annoyed me so I decided to get to the bottom of it but it took some time...
HenriAug wrote:I wonder if i can create a class that automates that stuff. You extend a base class, implement is draw() method and it takes care of that OnMessage and WM_PAINT and stuff.
You can definitely do it, you will probably encounter some issues along the way but in the end you can have something easy to use.
HenriAug
Posts: 11
Joined: 10 May 2017, 18:16

Re: iPhilip and transparent click through windows

30 Aug 2017, 15:36

HenriAug wrote:I wonder if i can create a class that automates that stuff. You extend a base class, implement is draw() method and it takes care of that OnMessage and WM_PAINT and stuff.
You can definitely do it, you will probably encounter some issues along the way but in the end you can have something easy to use.

Indeed i just found an issue that i can't solve

Code: Select all

class classDrawableWindow{
    name := ""

    __New(name){
        this.name := name
        WM_PAINT = 15
        seeIfItWorked := OnMessage(WM_PAINT, "repaint")
        TrayTip, , seeIfItWorked = [%seeIfItWorked%]
        ;you should see the function name between the brackets in case of success
    }

    repaint(){
        TrayTip, , this = %this%
    }
}
This doesn't work. I've found the thread can you call a class method with OnMessage ?. It seens it's not possible to do it the way i thought (or is it?)
If this is indeed the case how can i make an workaround?

I've read about Functors but could manage to get anything working (and i'm not sure if it is the way to go)
obeeb
Posts: 140
Joined: 20 Feb 2014, 19:15

Re: iPhilip and transparent click through windows

31 Aug 2017, 06:03

As documented in https://autohotkey.com/docs/objects/Fun ... er-Defined you can do the following:

Code: Select all

class classDrawableWindow{
	static WM_PAINT := 15

    __New(name){
        this.name := name        
        OnMessage(classDrawableWindow.WM_PAINT, this)
    }

    Call(){
        TrayTip, , % "this.name = " this.name
    }
}
HenriAug
Posts: 11
Joined: 10 May 2017, 18:16

Re: iPhilip and transparent click through windows

31 Aug 2017, 23:36

It worked! Thank you!

I almost got the setup done. I will post it here what i already have. After finishing it i will share in an dedicated thread :)

But right now something is intriguing me.

Code: Select all

class classDrawableWindow{
    static WM_ACTIVATE := 6
    static WM_PAINT := 15

    __New(name){
        ;I REALLY SHOULD CHECK FOR SPACES ON THE NAME 
        ;VARIABLE OTHERWISE Gui, %name%:cmd will NOT work
        this.name := name        
        OnMessage(classDrawableWindow.WM_PAINT, this)
        Gui, %name%:New, +LastFound +Resize, %name%
        w := A_ScreenWidth/3
        h := A_ScreenHeight/3
        Gui, %name%:Show, x0 y0 w%w% h%h%
        Gui, %name%:Color, FF0066
        ;Gui, 
    }

    Call(a1, a2, a3, a4){
        TrayTip, Arguments, a1 = %a1%`na2 = %a2%`na3 = %a3%`na4 = %a4%
        this.paint()
    }

    paint(){
        ;MsgBox, , paint(), % "painting " . this.name
        name := this.name
        Gui, %name%:Font, s10 C000000, Verdana
        Gui, %name%:Add, Text,, % "classDrawableWindow.paint() => " . this.name
    }
}

class classTestWindow extends classDrawableWindow{

    paint(){
        name := this.name
        Gui, %name%:Font, s10 C00FF00, Arial
        Gui, %name%:Add, Text,, % "classTestWindow.paint() => " . this.name
    }
}


^q::
    drawableWindow := new classDrawableWindow("drawableWindow")
return

^w::
    testWindow := new classTestWindow("testWindow")
        testWindow := new classTestWindow("testWindow2")
return

F1::
   Reload
return
When i open one window the other windows are painted like 4 or more times. Is that normal?
obeeb wrote:As documented in https://autohotkey.com/docs/objects/Fun ... er-Defined you can do the following:
Also i think i could not interpret this page. Because even after reading it over and over i don't get how you got to OnMessage(classDrawableWindow.WM_PAINT, this) hahah
maybe the examples were just not so clear. Or it's something so basic that it was not needed. Just to see if i got:

any object with an Call() method can be passed as a function?

Return to “Ask For Help”

Who is online

Users browsing this forum: Peter2, Rohwedder, RubbeH, Xtra and 51 guests