AHKathon! [AHK Hackathon] 12/17

Talk about anything
User avatar
jeeswg
Posts: 5284
Joined: 19 Dec 2016, 01:58
Location: UK

Re: AHKathon! [AHK Hackathon] 12/17

08 Dec 2017, 00:23

entry

Code: Select all

;entry by jeeswg for: AHKathon! [AHK Hackathon] 1-8 Dec 2017
;(no prize needed) (please post me a score)

;auto-click MS Paint, requires the Gdip library:
;GDI+ standard library 1.45 by tic - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=6517

;this will look good with various MS Paint settings,
;some recommended settings are as follows:

;MS Paint (Windows XP):
;choose Brush, choose the biggest of the 3 circles,
;choose red as the primary colour
;choose light green as the secondary colour

;MS Paint (Windows 7):
;choose Brush, (this is chosen by default),
;under Size, choose the biggest size,
;choose red as the primary colour
;choose light green as the secondary colour

;settings:
vDelay := 1
;vDelay := 0 ;lower values mean faster clicks

;==================================================

ListLines, Off
#NoEnv
AutoTrim, Off
SetBatchLines, -1

;create Esc hotkey to reload script
OnMessage(0x5555, "MsgMonitor")
OnExit("ExitFunc")

;ID_FILE_RELOADSCRIPT := 65400 ;ID_TRAY_RELOADSCRIPT := 65303
vScriptPID := DllCall("kernel32\GetCurrentProcessId", UInt)
vScript := "DetectHiddenWindows, On"
. "`r`n" "PostMessage, 0x5555, % A_ScriptHwnd,,, % ""ahk_id "" " A_ScriptHwnd
. "`r`n"
. "`r`n" "#IfWinActive, ahk_class MSPaintApp"
. "`r`n" "Esc::"
. "`r`n" "PostMessage, 0x111, 65400,,, % ""ahk_id "" " A_ScriptHwnd
;. "`r`n" "MsgBox, % ""hotkey subroutine ended, script reloaded"""
. "`r`n" "ExitApp"
. "`r`n"
. "`r`n" "^Esc::"
. "`r`n" "Process, Close, " vScriptPID
. "`r`n" "MsgBox, % ""script terminated"""
. "`r`n" "ExitApp"
ExecScript(vScript, 0)
return

;==================================================

q::
WinGet, hWnd, ID, A
WinGetClass, vWinClass, % "ahk_id " hWnd
if !(vWinClass = "MSPaintApp")
{
	MsgBox, % "error: MS Paint must be the active window"
	return
}

ControlGet, hCtl, Hwnd,, AfxFrameOrView42u1, % "ahk_id " hWnd
;e.g. Afx:00000000FF7A0000:81
;e.g. Afx:00000000FF0E0000:81
if !hCtl
{
	vCtlClassNN := JEE_WinGetCtlClassNNRegEx(hWnd, "Afx:00000000....0000:8")
	ControlGet, hCtl, Hwnd,, % vCtlClassNN, % "ahk_id " hWnd
}
if !hCtl
{
	MsgBox, % "error: no canvas control found"
	return
}

WinGetPos, vWinX, vWinY, vWinW, vWinH, % "ahk_id " hCtl
if (vWinW < 925) || (vWinH < 180)
{
	MsgBox, % "error: canvas size is too small, recommend at least: w925 h180"
	return
}

CoordMode, Mouse, Screen
pToken := Gdip_Startup()
vText := "abcdefghijklmnopqrstuvwxyz"
vText := "AutoHotkey"
hFont := JEE_FontCreate("Courier New", 28, "b")
JEE_ImgTextToImg(vText, hFont, "", hBitmap, pBitmap)
Gdip_GetImageDimensions(pBitmap, vImgW, vImgH)
;MsgBox, % vImgW " " vImgH
oArray := []
oArray.SetCapacity(vImgW*vImgH)
Loop, % vImgH
{
	vY := A_Index-1
	Loop, % vImgW
	{
		vX := A_Index-1
		vCol := Gdip_GetPixel(pBitmap, vX, vY)
		if !(vCol = 0xFFFFFFFF)
			oArray.Push([vX,vY])
	}
}
;MsgBox, % oArray.Length()
if (vDelay = "")
	vDelay := 1
SetMouseDelay, % vDelay
Loop, % oArray.Length()
{
	WinGet, hWnd2, ID, A
	if !(hWnd = hWnd2)
		return
	if !oArray.Length()
		break
	Random, vNum, 1, % oArray.Length()
	Random, vNum2, 1, 2
	vX := vWinX + 25 + oArray[vNum].1*4
	vY := vWinY + 20 + oArray[vNum].2*4
	vBtn := (vNum2 = 1) ? "L" : "R"
	MouseClick, % vBtn, % vX, % vY, 1, 0
	oArray.RemoveAt(vNum)
}
;MsgBox, % oArray.Length()
SoundBeep
DeleteObject(hBitmap)
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
return

;==================================================

JEE_ImgTextToImg(vText, hFont, vOpt:="", ByRef hBitmap:="", ByRef pBitmap:="", vColText:="", vColBk:="")
{
	if (vOpt = "x")
		vFunc := "JEE_GdipStartup", pToken := %vFunc%()

	;measure text as image
	hDC := DllCall("gdi32\CreateCompatibleDC", Ptr,0, Ptr)
	DllCall("gdi32\SelectObject", Ptr,hDC, Ptr,hFont, Ptr)
	VarSetCapacity(RECT, 16, 0)

	;didn't work
	;if !(vColText = "")
	;	DllCall("gdi32\SetTextColor", Ptr,hDC, UInt,vColText)
	;if !(vColBk = "")
	;	DllCall("gdi32\SetBkColor", Ptr,hDC, UInt,vColBk)

	;DT_CALCRECT := 0x400
	DllCall("user32\DrawText", Ptr,hDC, Str,vText, Int,-1, Ptr,&RECT, UInt,0x400)
	vImgW := NumGet(&RECT, 8, "Int")
	vImgH := NumGet(&RECT, 12, "Int")

	;create text as image
	hBitmap := DllCall("gdi32\CreateCompatibleBitmap", Ptr,hDC, Int,vImgW, Int,vImgH, Ptr)
	DllCall("gdi32\SelectObject", Ptr,hDC, Ptr,hBitmap, Ptr)
	VarSetCapacity(RECT, 16, 0)
	;DT_NOCLIP := 0x100
	DllCall("user32\DrawText", Ptr,hDC, Str,vText, Int,-1, Ptr,&RECT, UInt,0x100)
	DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", Ptr,hBitmap, Ptr,0, PtrP,pBitmap)
	DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", Ptr,pBitmap, PtrP,hBitmap, UInt,0xffffffff)
	if !IsByRef(pBitmap)
		DllCall("gdiplus\GdipDisposeImage", Ptr,pBitmap)

	if (vOpt = "x")
		vFunc := "JEE_GdipShutdown", %vFunc%(pToken)
}

;==================================================

JEE_FontCreate(vName, vSize, vFontStyle:="", vWeight:="")
{
	vHeight := -DllCall("kernel32\MulDiv", Int,vSize, Int,A_ScreenDPI, Int,72)
	vWidth := 0
	vEscapement := 0
	vOrientation := 0
	vWeight := (InStr(vFontStyle, "b") && (vWeight="")) ? 700 : 400
	vItalic := InStr(vFontStyle, "i") ? 1 : 0
	vUnderline := InStr(vFontStyle, "u") ? 1 : 0
	vStrikeOut := InStr(vFontStyle, "s") ? 1 : 0
	vCharSet := 0
	vOutPrecision := 0
	vClipPrecision := 0
	vQuality := 0
	vPitchAndFamily := 0
	vFaceName := vName
	vOutPrecision := 3
	vClipPrecision := 2
	vQuality := 1
	vPitchAndFamily := 34
	return DllCall("gdi32\CreateFont", Int,vHeight, Int,vWidth, Int,vEscapement, Int,vOrientation, Int,vWeight, UInt,vItalic, UInt,vUnderline, UInt,vStrikeOut, UInt,vCharSet, UInt,vOutPrecision, UInt,vClipPrecision, UInt,vQuality, UInt,vPitchAndFamily, Str,vFaceName, Ptr)
}

;==================================================

JEE_WinGetCtlClassNNRegEx(hWnd, vClassRegEx, vNum:=1)
{
	vCount := 0
	WinGet, vCtlList, ControlList, % "ahk_id " hWnd
	Loop, Parse, vCtlList, `n
	{
		vCtlClassNN := A_LoopField
		ControlGet, hCtl, Hwnd,, % vCtlClassNN, % "ahk_id " hWnd
		WinGetClass, vCtlClass, % "ahk_id " hCtl
		if RegExMatch(vCtlClass, vClassRegEx)
			vCount++
		if (vCount = vNum)
			return vCtlClassNN
	}
}

;==================================================

;Run / RunWait
;https://autohotkey.com/docs/commands/Run.htm

; ExecScript: Executes the given code as a new AutoHotkey process.
ExecScript(Script, Wait:=true)
{
    shell := ComObjCreate("WScript.Shell")
    exec := shell.Exec("AutoHotkey.exe /ErrorStdOut *")
    exec.StdIn.Write(script)
    exec.StdIn.Close()
    if Wait
        return exec.StdOut.ReadAll()
}

;==================================================

MsgMonitor(wParam, lParam, msg)
{
	global vScriptHwnd2
	vScriptHwnd2 := wParam
}

;==================================================

ExitFunc()
{
	global vScriptHwnd2
	DetectHiddenWindows, On
	WinClose, % "ahk_id " vScriptHwnd2
}

;==================================================
User avatar
boiler
Posts: 2372
Joined: 21 Dec 2014, 02:44

Re: AHKathon! [AHK Hackathon] 12/17

08 Dec 2017, 00:31

It says my canvas size is too small even though it's larger than the recommended size.
User avatar
jeeswg
Posts: 5284
Joined: 19 Dec 2016, 01:58
Location: UK

Re: AHKathon! [AHK Hackathon] 12/17

08 Dec 2017, 01:15

- Could you report what the XYWH values are. Thanks.
MsgBox, % Clipboard := Format("x{} y{} w{} h{}", vWinX, vWinY, vWinW, vWinH)
vWinW and vWinH don't really matter, but the script needs values for vWinX and vWinY.
- You could comment out the lines that check the canvas size and see if the script works. You could also increase the delay as a safety feature.
- Which OS do you use? I've already tried quite hard to make this work on Paint for Windows XP and 7, and to take into account a ClassNN that varies.
User avatar
waetherman
Posts: 112
Joined: 05 Feb 2016, 17:00

Re: AHKathon! [AHK Hackathon] 12/17

08 Dec 2017, 03:42

- Could you report what the XYWH values are. Thanks.
MsgBox, % Clipboard := Format("x{} y{} w{} h{}", vWinX, vWinY, vWinW, vWinH)
vWinW and vWinH don't really matter, but the script needs values for vWinX and vWinY.
- You could comment out the lines that check the canvas size and see if the script works. You could also increase the delay as a safety feature.
- Which OS do you use? I've already tried quite hard to make this work on Paint for Windows XP and 7, and to take into account a ClassNN that varies.
I have same problem.
x0 y139 w0 h880
https://i.imgur.com/7ogpfhn.png
Image
User avatar
jeeswg
Posts: 5284
Joined: 19 Dec 2016, 01:58
Location: UK

Re: AHKathon! [AHK Hackathon] 12/17

08 Dec 2017, 04:06

Do either of you use Windows 10? Windows 10 seems to have problems with everything, particularly standard MS apps like Calculator. Try commenting out the lines that check the canvas size and specifying values of vWinX and vWinY approximately where the canvas begins.
User avatar
waetherman
Posts: 112
Joined: 05 Feb 2016, 17:00

Re: AHKathon! [AHK Hackathon] 12/17

08 Dec 2017, 05:47

Do either of you use Windows 10? Windows 10 seems to have problems with everything, particularly standard MS apps like Calculator. Try commenting out the lines that check the canvas size and specifying values of vWinX and vWinY approximately where the canvas begins.
W10 indeed! Your script is pretty neat and pretty much outclassed other scripts in the competition for a 2nd place (1st goes to Cap of course). You can somewhat support W10 by replacing

Code: Select all

WinGetPos, vWinX, vWinY, vWinW, vWinH, % "ahk_id " hCtl
if (vWinW < 925) || (vWinH < 180)
{
	MsgBox, % "error: canvas size is too small, recommend at least: w925 h180"
	return
}
with

Code: Select all

WinGetPos, vWinX, vWinY, vWinW, vWinH, % "ahk_id " hCtl

if (vWinW < 925) || (vWinH < 180)
{
	MsgBox 5, Wrong dimensions, % "error: You use Win 10 or canvas size is too small, recommend at least: w925 h180`nIf you use Win10, click 'retry' and the script will set defaults size automatically"
	IfMsgBox Retry
	{
		WinMove % "ahk_id " hWnd,, 0, 0, 1100, 500
		send ^w
		WinWait Resize and Skew ahk_class #32770 ahk_exe mspaint.exe
		send {right}{Tab}1000{Tab}{Tab}{Space}+{Tab}280{Enter}
		vWinX := 30
		vWinY := 200
		vWinW := 925
		vWinH := 180
	}
	else
	{
		return
	}
}
Image
User avatar
Capn Odin
Posts: 1290
Joined: 23 Feb 2016, 19:45
Location: Denmark

Re: AHKathon! [AHK Hackathon] 12/17

08 Dec 2017, 15:58

This is not my entry.

Code: Select all

#Include AutoColourClickerClass.ahk

SetBatchLines -1

lst := []

RButton & LButton::
	Critical
	lst.Push(new AutoColourClicker())
	MouseGetPos, x, y
	While(GetKeyState("LButton", "P")) {
		MouseGetPos, x2, y2
		if(oldx2 != x2 && oldy2 != y2) {
			lst[lst.MaxIndex()].Draw(x, y, x2 - x, y2 - y)
			oldx2 := x2
			oldy2 := y2
		}
	}
	lst[lst.MaxIndex()].Fade()
	lst[lst.MaxIndex()].MakeOptionGUI()
return

RButton::RButton

z::Pause

Code: Select all

#Include <Gdip>

OnExit("GdiCleanUp")

if(!pToken := Gdip_Startup()) {
	MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
	ExitApp
}

CoordMode, Mouse, Screen
CoordMode, Pixel, Screen

Class AutoColourClicker {
	Static id := 0
	Frequency := 100
	Colour := 0x303030
	timer := False
	bool := False
	r := 5
	
	__New(){
		AutoColourClicker.id++
		this.MakeGUI()
	}
	
	MakeGUI() {
		Global
		Gui, New, -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop +HwndHwnd -DPIScale
		Gui, Show, NA
		OnMessage(0x201, ObjBindMethod(this, "WM_LBUTTONDOWN"))
		this.hdc := CreateCompatibleDC()
		UpdateLayeredWindow(this.hwnd, this.hdc)
		this.hwnd := Hwnd
	}
	
	MakeOptionGUI() {
		Global
		Gui, New, +HwndOpHwnd +AlwaysOnTop +ToolWindow -DPIScale, % "AutoColourClicker nr. " AutoColourClicker.id 
		Gui, Add, Text, w55, Colour:
		Gui, Add, Edit, x+m yp-4 w100 +HwndColourHwnd
		Gui, Add, Text, xs w55, Frequency:
		Gui, Add, Edit, x+m yp-4 w100 +HwndFrequencyHwnd
		Gui, Add, Button, xs w165 +HwndButtonHwnd, Start Timer
		Gui, Add, Button, ys y0 h80 +HwndColourPickerHwnd, Pick Colour
		this.AddGlabel(ColourHwnd, "SetGuiVal" , ColourHwnd, "Colour")
		this.AddGlabel(FrequencyHwnd, "SetGuiVal", FrequencyHwnd, "Frequency")
		this.AddGlabel(ColourPickerHwnd, "PickColour")
		this.AddGlabel(ButtonHwnd, "SetTimer", "On")
		this.OptionHwnd := OpHwnd
		this.ColourHwnd := ColourHwnd
		MouseGetPos, x, y
		Gui, Show, % "AutoSize x" x " y" y
	}
	
	PickColour() {
		var := this.timer := Func("PickColour").Bind(this)
		Hotkey, LButton, % var, ON
	}
	
	SetTimer(frequency := "On") {
		if(this.timer) {
			var := this.timer
			SetTimer, % var, Off
		}
		var := this.timer := Func("ClickTimer").Bind(this)
		SetTimer, % var, % frequency = "On" ? this.Frequency : frequency
	}
	
	AddGlabel(Hwnd, Func, Pars*) {
		Global
		__var__ := ObjBindMethod(this, Func, Pars*)
		GuiControl +g, % Hwnd, % __var__
	}
	
	SetGuiVal(hwnd, str) {
		ControlGetText, val, , % "ahk_id " hwnd
		this[str] := val
	}
	
	Draw(x, y, w, h) {
		Critical
		this.x := x
		this.y := y
		this.w := w
		this.h := h
		this.a := 55
		
		hbm := CreateDIBSection(w + this.r, h + this.r)
		obm := SelectObject(this.hdc, hbm)
		G := Gdip_GraphicsFromHDC(this.hdc)
		
		pBrush := Gdip_BrushCreateSolid(this.GetColour("8F00FF", this.a))
		pPen := Gdip_CreatePenFromBrush(pBrush, 5)
		
		Gdip_FillRoundedRectangle(G, pBrush, this.r/2, this.r/2, w, h, this.r)
		Gdip_DrawRoundedRectangle(G, pPen, this.r/2, this.r/2, w, h, this.r)
		
		UpdateLayeredWindow(this.hwnd, this.hdc, x, y, w + this.r, h + this.r)
		
		DeleteObject(obm)
		Gdip_ReleaseDC(G, this.hdc)
		Gdip_DeletePen(pPen)
		Gdip_DeleteBrush(pBrush)
		Gdip_DeleteGraphics(G)
	}
	
	GetHex(number) {
		return Format("{:02X}", number)
	}
	
	GetColour(colour, alpha := 0xFF) {
		return "0x" this.GetHex(alpha) colour
	}
	
	WM_LBUTTONDOWN(wParam, lParam, msg, hwnd) {
		if(hwnd == this.hwnd) {
			PostMessage, 0xA1, 2, , , % "ahk_id " this.hwnd
			this.bool := True
		}
	}
	
	UpdatePos() {
		WinGetPos, x, y, w, h, % "ahk_id " this.hwnd
		if(!GetKeyState("LButton", "P")) {
			this.bool := False
		}
		this.x := x
		this.y := y
		this.w := w
		this.h := h
	}
	
	Fade(in := False) {
		pBrush := Gdip_BrushCreateSolid(0x558F00FF)
		pPen := Gdip_CreatePenFromBrush(pBrush, 5)
		G := Gdip_GraphicsFromHDC(this.hdc)
		loop % this.a / 2 {
			Gdip_GraphicsClear(G)
			if(this.a > 5) {
				pBrushAlpha := Gdip_BrushCreateSolid(this.GetColour("8F00FF", this.a -= 2))
				Gdip_FillRoundedRectangle(G, pBrushAlpha, this.r/2, this.r/2, this.w, this.h, this.r)
			}
			Gdip_DrawRoundedRectangle(G, pPen, this.r/2, this.r/2, this.w, this.h, this.r)
			UpdateLayeredWindow(this.hwnd, this.hdc)
			Gdip_DeleteBrush(pBrushAlpha)
			Sleep, 20
		}
		Gdip_ReleaseDC(G, this.hdc)
		Gdip_DeleteGraphics(G)
		Gdip_DeletePen(pPen)
		Gdip_DeleteBrush(pBrush)
	}
}

ClickTimer(obj) {
	Critical
	if(obj.bool) {
		obj.UpdatePos()
	}
	PixelSearch, x, y, % obj.x + obj.r, % obj.y + obj.r, % obj.x + obj.w, % obj.y + obj.h, % obj.Colour, 5, Fast RGB
	if(!ErrorLevel) {
		Click, % x ", " y
	}
}

PickColour(obj) {
	Critical
	MouseGetPos, x, y
	PixelGetColor, colour, % x, % y, RGB
	obj.Colour := colour
	Hotkey, LButton, Off
	ControlSetText , , % colour, % "ahk_id " obj.ColourHwnd
}

GuiClose(GuiHwnd) {
	Global lst
	for i, v in lst {
		if(v.OptionHwnd == GuiHwnd) {
			v.SetTimer("Off")
			DeleteDC(v.hdc)
			Gui, % v.Hwnd ":Default"
			Gui, Destroy
			lst.RemoveAt(i)
			Break
		}
	}
}

GdiCleanUp() {
	Global pToken
	Gdip_Shutdown(pToken)
}
Image
Last edited by Capn Odin on 08 Dec 2017, 19:13, edited 7 times in total.
Please excuse my spelling I am dyslexic.
User avatar
Capn Odin
Posts: 1290
Joined: 23 Feb 2016, 19:45
Location: Denmark

Re: AHKathon! [AHK Hackathon] 12/17

08 Dec 2017, 16:35

ImageImage
Please excuse my spelling I am dyslexic.
User avatar
Micromegas
Posts: 189
Joined: 28 Apr 2015, 23:02
Location: Germany

Re: AHKathon! [AHK Hackathon] 12/17

08 Dec 2017, 18:51

For my entry, I took the liberty to deviate quite a bit from the task. Instead of auto-click, for which I have not felt a need so far, I wrote CheeseCrumbs, a recorder that looks around the place where you click, records the bitmap, and creates code to insert that into any script you're writing. By "cheese crumbs", I mean the little bitmaps, which lead to the execution of the script you're writing like breadcrumbs were supposed to lead Hansel and Gretel out of the forest.

Code: Select all

; ========================================
; CheeseCrumbs
; Bitmap recorder for AutoHotkey
; created by Micromegas for the AHKathon 
; December 2017
; ========================================

; ========================================
; General settings
; ========================================

; These are the usual ones, nothing special here:
#NoEnv  ; 
; #Warn  ; disabled because of Gdip.ahk
SendMode Input  
SetWorkingDir %A_ScriptDir%  
#SingleInstance force

; These are set to the whole screen to allow recording everywhere. 
CoordMode, Pixel, Screen
CoordMode, Mouse, Screen

; GDI+ standard library 1.45 by tic (https://autohotkey.com/board/topic/29449-gdi-standard-library-145-by-tic/)
#Include, %A_ScriptDir%\Gdip.ahk

; ========================================
; Global definitions
; ========================================

global crumbfolder:=A_WorkingDir . "\crumbs\"
global crumbwidth:=64
global crumbheight:=64

; limits of area to be searched:
global SearchX0:=0
global SearchY0:=0
global SearchX1:=0
global SearchY1:=0
SysGet, SearchX1, 78
SysGet, SearchY1, 79

global RecordedCommands:=""
global clicknow:=0
global shades:=180
global mousespeed=20	; slow it down a bit for demonstration purposes

; Initiate graphics
pTok:=Gdip_Startup()

; ========================================
; Build and display main dialog
; ========================================

Gui, Add, Text, , With Ctrl key pressed, select where you want the mouseclick recorded. `nYou can simply click to use the current size (initially %crumbwidth%*%crumbheight%) or drag the mouse to define a rectangle. `nInitially the search area is all screens. You can redefine that with Alt + mouse drag. `nNote that the area needs to be big enough to to contain the cheesecrumb size, even at its edges. `n	
	; I would like to add current values, but I don't know how to update that.
Gui, Add, Text, , &Tolerance:
Gui, Add, Edit, vshades x120 y+-12 w200, %shades%
Gui, Add, Checkbox, vclicknow xm, E&xecute click right away 
Gui, Add, Button, default, Save to clipboard  ; Run the label ButtonSaveToClipboard when button is pressed.
Gui, Add, Button, x+20, Close

Gui, Show,, CheeseCrumbs mouse click recorder

; create file for cheesecrumbs, if it doesn't exist
if !InStr(FileExist(crumbfolder), "D") {
	FileCreateDir, %crumbfolder%
}
Return

; ========================================
; Record click
; ========================================

^LButton::
	MouseGetPos mouseX, mouseY, mousewin, mousecontrol
	Gui, Submit, NoHide	; 
	Return

^LButton up::
	MouseGetPos mouseupX, mouseupY, mousewin, mousecontrol

	x0 := Min(mouseupX,mouseX)
	y0 := Min(mouseupY,mouseY)
	if (Abs(mouseupX-mouseX)>=8 and Abs(mouseupY-mouseY)>=8) {	; Allow some wiggle room so user doesn't accidentally define the crumb too small
		; Redefine crumb size
		crumbwidth := Abs(mouseupX-mouseX)
		crumbheight := Abs(mouseupY-mouseY)
	}

	;Check bounds
	if (x0<SearchX0 or y0<SearchY0 or x0+crumbwidth>SearchX1 or  y0+crumbheight>SearchY1) {
		MsgBox You clicked outside the search area. (You can redefine the search area with Alt + mouse drag.)
		Return
	}

	;Capture screen
	pBmp:=Gdip_BitmapFromScreen(x0-crumbwidth/2 "|" y0-crumbheight/2 "|" crumbwidth "|" crumbheight)
	crumbfile:=GetNewFilename(10000*x0+y0)
	Gdip_SaveBitmapToFile(pBmp, crumbfile)
	RecordClick(crumbfile) 
	if (clicknow) 
		Click x0,y0
	Return

RecordClick(f) {
	RecordedCommands .= Format("ImageSearch x, y, {1}, {2}, {3}, {4}, *{5} {6}`n", SearchX0, SearchY0, SearchX1, SearchY1, shades, f) 
	. Format("MouseMove x+{1}/2, y+{2}/2, (3)`n", crumbwidth, crumbheight,, mousespeed)
	. "Click`n"
}

; ========================================
; Defining the area to be searched
; ========================================

!LButton::
	MouseGetPos mouseX, mouseY, mousewin, mousecontrol
	Return

!LButton up::
	MouseGetPos mouseupX, mouseupY, mousewin, mousecontrol
	if (Abs(mouseupX-mouseX)<=crumbwidth or Abs(mouseupY-mouseY)<=crumbheight) {
		MsgBox The area to be searched must be bigger than the current crumb size (%crumbheight%*%crumbwidth%). 
		Return
	}
	SearchX0 := Min(mouseupX,mouseX)
	SearchY0 := Min(mouseupY,mouseY)
	SearchX1 := Max(mouseupX,mouseX)
	SearchY1 := Max(mouseupY,mouseY)
	Return

; ========================================
; Functions
; ========================================

; This function allows to enter just the clicks without having to worry about filenames. 
; todo: Allow user to change the name to something friendly and also to reuse any existing files. 
GetNewFilename(suggestion) {
	local n:=suggestion
	local f:= FilenameFromNumber(n)
	While (FileExist(f)) {	; if it exists, simply add one to the number so it remains unique.
		n++
		f:= FilenameFromNumber(n)
	}
	return f
}

; This function just defines the file name format. 
FilenameFromNumber(n) {
	global crumbfolder
	return crumbfolder . Format("{1:08u}",n) . ".png"
}

ButtonSaveToClipboard:
	clipboard := RecordedCommands
	RecordedCommands:=""
	Return

ButtonClose:
	Gdip_Shutdown(pTok)
	ExitApp

; ========================================
; Generally useful functions
; ========================================
Min(x,y) {
	if (x>y)
		return y
	else 
		return x
}

Max(x,y) {
	if (x>y)
		return x
	else 
		return y
}
User avatar
Capn Odin
Posts: 1290
Joined: 23 Feb 2016, 19:45
Location: Denmark

Re: AHKathon! [AHK Hackathon] 12/17

08 Dec 2017, 18:56

For my entry, I took the liberty to deviate quite a bit from the task. Instead of auto-click, for which I have not felt a need so far, I wrote CheeseCrumbs, a recorder that looks around the place where you click, records the bitmap, and creates code to insert that into any script you're writing. By "cheese crumbs", I mean the little bitmaps, which lead to the execution of the script you're writing like breadcrumbs were supposed to lead Hansel and Gretel out of the forest.
This is pretty neat.
Please excuse my spelling I am dyslexic.
Helgef
Posts: 3231
Joined: 17 Jul 2016, 01:02
Contact:

Re: AHKathon! [AHK Hackathon] 12/17

08 Dec 2017, 20:45

AntiClick
This program protects against injected mouse events.

How to
Select the events you want to block in the settings dialog, optionally, allow AHK generated events. Settings can be accessed via the tray menu. Script can be exited via esc or tray menu.

Limitations
  • Doesn't block messages sent directly to a window.
  • Nearly untested.
Download
This is my entry, I do not want any rewards.
AntiClick.rar
File contents:
AntiClick.ahk
includes\globalsAndConstants.ahk
includes\gui.ahk
includes\mouseHook.ahk
includes\settings.ahk
settings\settings.ini (created)
(5.1 KiB) Downloaded 23 times

Cheers.
User avatar
Masonjar13
Posts: 1403
Joined: 20 Jul 2014, 10:16
GitHub: Masonjar13
Location: Не Россия

Re: AHKathon! [AHK Hackathon] 12/17

08 Dec 2017, 21:06

And that's time! Bit late actually, but no problem, started late accidentally anyway. :P All entries have been taken and no more will be accepted. I'll score them and post the winners asap :thumbup:
User avatar
Micromegas
Posts: 189
Joined: 28 Apr 2015, 23:02
Location: Germany

Re: AHKathon! [AHK Hackathon] 12/17

09 Dec 2017, 12:02

How does one actually (Hi waetherman ;) ) pronounce the name "AHKathon"? "a hackathlon" or Ay-eitch-kay-athlon?
User avatar
Capn Odin
Posts: 1290
Joined: 23 Feb 2016, 19:45
Location: Denmark

Re: AHKathon! [AHK Hackathon] 12/17

09 Dec 2017, 12:08

I pronounce the AHK as the individual characters in danish and the rest as athon. The name of the char H in english feel unnatural to me, so I guess I unconsciously avoid it.
Please excuse my spelling I am dyslexic.
User avatar
waetherman
Posts: 112
Joined: 05 Feb 2016, 17:00

Re: AHKathon! [AHK Hackathon] 12/17

09 Dec 2017, 18:17

I pronounce it Ah-cat-on
Image
Helgef
Posts: 3231
Joined: 17 Jul 2016, 01:02
Contact:

Re: AHKathon! [AHK Hackathon] 12/17

13 Dec 2017, 06:46

By popular demand (n=1), I will make a brief comment on what I mean with injected mouse events. It simply means mouse events not generated by actual use of a mouse, specifically mouse events generated by windows function such as sendInput or mouse_event. Typical use cases would be when you run code from the help forum, protecting you against scripts that starts making clicks here and there. But potentally also could protect against malicious software, I guess that is pretty rare though.

Cheers.
User avatar
Micromegas
Posts: 189
Joined: 28 Apr 2015, 23:02
Location: Germany

Re: AHKathon! [AHK Hackathon] 12/17

13 Dec 2017, 14:42

Thanks, Helgef!
Georgie Munteer

Re: AHKathon! [AHK Hackathon] 12/17

16 Dec 2017, 02:37

entry

Code: Select all

;entry by jeeswg for: AHKathon! [AHK Hackathon] 1-8 Dec 2017
;(no prize needed) (please post me a score)

;auto-click MS Paint, requires the Gdip library:
;GDI+ standard library 1.45 by tic - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=6517

;this will look good with various MS Paint settings,
;some recommended settings are as follows:

;MS Paint (Windows XP):
;choose Brush, choose the biggest of the 3 circles,
;choose red as the primary colour
;choose light green as the secondary colour

;MS Paint (Windows 7):
;choose Brush, (this is chosen by default),
;under Size, choose the biggest size,
;choose red as the primary colour
;choose light green as the secondary colour

;settings:
vDelay := 1
;vDelay := 0 ;lower values mean faster clicks

;==================================================

ListLines, Off
#NoEnv
AutoTrim, Off
SetBatchLines, -1

;create Esc hotkey to reload script
OnMessage(0x5555, "MsgMonitor")
OnExit("ExitFunc")

;ID_FILE_RELOADSCRIPT := 65400 ;ID_TRAY_RELOADSCRIPT := 65303
vScriptPID := DllCall("kernel32\GetCurrentProcessId", UInt)
vScript := "DetectHiddenWindows, On"
. "`r`n" "PostMessage, 0x5555, % A_ScriptHwnd,,, % ""ahk_id "" " A_ScriptHwnd
. "`r`n"
. "`r`n" "#IfWinActive, ahk_class MSPaintApp"
. "`r`n" "Esc::"
. "`r`n" "PostMessage, 0x111, 65400,,, % ""ahk_id "" " A_ScriptHwnd
;. "`r`n" "MsgBox, % ""hotkey subroutine ended, script reloaded"""
. "`r`n" "ExitApp"
. "`r`n"
. "`r`n" "^Esc::"
. "`r`n" "Process, Close, " vScriptPID
. "`r`n" "MsgBox, % ""script terminated"""
. "`r`n" "ExitApp"
ExecScript(vScript, 0)
return

;==================================================

q::
WinGet, hWnd, ID, A
WinGetClass, vWinClass, % "ahk_id " hWnd
if !(vWinClass = "MSPaintApp")
{
	MsgBox, % "error: MS Paint must be the active window"
	return
}

ControlGet, hCtl, Hwnd,, AfxFrameOrView42u1, % "ahk_id " hWnd
;e.g. Afx:00000000FF7A0000:81
;e.g. Afx:00000000FF0E0000:81
if !hCtl
{
	vCtlClassNN := JEE_WinGetCtlClassNNRegEx(hWnd, "Afx:00000000....0000:8")
	ControlGet, hCtl, Hwnd,, % vCtlClassNN, % "ahk_id " hWnd
}
if !hCtl
{
	MsgBox, % "error: no canvas control found"
	return
}

WinGetPos, vWinX, vWinY, vWinW, vWinH, % "ahk_id " hCtl
if (vWinW < 925) || (vWinH < 180)
{
	MsgBox, % "error: canvas size is too small, recommend at least: w925 h180"
	return
}

CoordMode, Mouse, Screen
pToken := Gdip_Startup()
vText := "abcdefghijklmnopqrstuvwxyz"
vText := "AutoHotkey"
hFont := JEE_FontCreate("Courier New", 28, "b")
JEE_ImgTextToImg(vText, hFont, "", hBitmap, pBitmap)
Gdip_GetImageDimensions(pBitmap, vImgW, vImgH)
;MsgBox, % vImgW " " vImgH
oArray := []
oArray.SetCapacity(vImgW*vImgH)
Loop, % vImgH
{
	vY := A_Index-1
	Loop, % vImgW
	{
		vX := A_Index-1
		vCol := Gdip_GetPixel(pBitmap, vX, vY)
		if !(vCol = 0xFFFFFFFF)
			oArray.Push([vX,vY])
	}
}
;MsgBox, % oArray.Length()
if (vDelay = "")
	vDelay := 1
SetMouseDelay, % vDelay
Loop, % oArray.Length()
{
	WinGet, hWnd2, ID, A
	if !(hWnd = hWnd2)
		return
	if !oArray.Length()
		break
	Random, vNum, 1, % oArray.Length()
	Random, vNum2, 1, 2
	vX := vWinX + 25 + oArray[vNum].1*4
	vY := vWinY + 20 + oArray[vNum].2*4
	vBtn := (vNum2 = 1) ? "L" : "R"
	MouseClick, % vBtn, % vX, % vY, 1, 0
	oArray.RemoveAt(vNum)
}
;MsgBox, % oArray.Length()
SoundBeep
DeleteObject(hBitmap)
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
return

;==================================================

JEE_ImgTextToImg(vText, hFont, vOpt:="", ByRef hBitmap:="", ByRef pBitmap:="", vColText:="", vColBk:="")
{
	if (vOpt = "x")
		vFunc := "JEE_GdipStartup", pToken := %vFunc%()

	;measure text as image
	hDC := DllCall("gdi32\CreateCompatibleDC", Ptr,0, Ptr)
	DllCall("gdi32\SelectObject", Ptr,hDC, Ptr,hFont, Ptr)
	VarSetCapacity(RECT, 16, 0)

	;didn't work
	;if !(vColText = "")
	;	DllCall("gdi32\SetTextColor", Ptr,hDC, UInt,vColText)
	;if !(vColBk = "")
	;	DllCall("gdi32\SetBkColor", Ptr,hDC, UInt,vColBk)

	;DT_CALCRECT := 0x400
	DllCall("user32\DrawText", Ptr,hDC, Str,vText, Int,-1, Ptr,&RECT, UInt,0x400)
	vImgW := NumGet(&RECT, 8, "Int")
	vImgH := NumGet(&RECT, 12, "Int")

	;create text as image
	hBitmap := DllCall("gdi32\CreateCompatibleBitmap", Ptr,hDC, Int,vImgW, Int,vImgH, Ptr)
	DllCall("gdi32\SelectObject", Ptr,hDC, Ptr,hBitmap, Ptr)
	VarSetCapacity(RECT, 16, 0)
	;DT_NOCLIP := 0x100
	DllCall("user32\DrawText", Ptr,hDC, Str,vText, Int,-1, Ptr,&RECT, UInt,0x100)
	DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", Ptr,hBitmap, Ptr,0, PtrP,pBitmap)
	DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", Ptr,pBitmap, PtrP,hBitmap, UInt,0xffffffff)
	if !IsByRef(pBitmap)
		DllCall("gdiplus\GdipDisposeImage", Ptr,pBitmap)

	if (vOpt = "x")
		vFunc := "JEE_GdipShutdown", %vFunc%(pToken)
}

;==================================================

JEE_FontCreate(vName, vSize, vFontStyle:="", vWeight:="")
{
	vHeight := -DllCall("kernel32\MulDiv", Int,vSize, Int,A_ScreenDPI, Int,72)
	vWidth := 0
	vEscapement := 0
	vOrientation := 0
	vWeight := (InStr(vFontStyle, "b") && (vWeight="")) ? 700 : 400
	vItalic := InStr(vFontStyle, "i") ? 1 : 0
	vUnderline := InStr(vFontStyle, "u") ? 1 : 0
	vStrikeOut := InStr(vFontStyle, "s") ? 1 : 0
	vCharSet := 0
	vOutPrecision := 0
	vClipPrecision := 0
	vQuality := 0
	vPitchAndFamily := 0
	vFaceName := vName
	vOutPrecision := 3
	vClipPrecision := 2
	vQuality := 1
	vPitchAndFamily := 34
	return DllCall("gdi32\CreateFont", Int,vHeight, Int,vWidth, Int,vEscapement, Int,vOrientation, Int,vWeight, UInt,vItalic, UInt,vUnderline, UInt,vStrikeOut, UInt,vCharSet, UInt,vOutPrecision, UInt,vClipPrecision, UInt,vQuality, UInt,vPitchAndFamily, Str,vFaceName, Ptr)
}

;==================================================

JEE_WinGetCtlClassNNRegEx(hWnd, vClassRegEx, vNum:=1)
{
	vCount := 0
	WinGet, vCtlList, ControlList, % "ahk_id " hWnd
	Loop, Parse, vCtlList, `n
	{
		vCtlClassNN := A_LoopField
		ControlGet, hCtl, Hwnd,, % vCtlClassNN, % "ahk_id " hWnd
		WinGetClass, vCtlClass, % "ahk_id " hCtl
		if RegExMatch(vCtlClass, vClassRegEx)
			vCount++
		if (vCount = vNum)
			return vCtlClassNN
	}
}

;==================================================

;Run / RunWait
;https://autohotkey.com/docs/commands/Run.htm

; ExecScript: Executes the given code as a new AutoHotkey process.
ExecScript(Script, Wait:=true)
{
    shell := ComObjCreate("WScript.Shell")
    exec := shell.Exec("AutoHotkey.exe /ErrorStdOut *")
    exec.StdIn.Write(script)
    exec.StdIn.Close()
    if Wait
        return exec.StdOut.ReadAll()
}

;==================================================

MsgMonitor(wParam, lParam, msg)
{
	global vScriptHwnd2
	vScriptHwnd2 := wParam
}

;==================================================

ExitFunc()
{
	global vScriptHwnd2
	DetectHiddenWindows, On
	WinClose, % "ahk_id " vScriptHwnd2
}

;==================================================
I like all entries but yours would be my number one pick, talk about outside the box thinking :thumbup:
User avatar
Masonjar13
Posts: 1403
Joined: 20 Jul 2014, 10:16
GitHub: Masonjar13
Location: Не Россия

Re: AHKathon! [AHK Hackathon] 12/17

29 Dec 2017, 11:19

Hey everyone, quick update for you: I ended up leaving sooner than later (by almost a month), so I won't be able to score them til after I get back home on the 8th. Thank you for your patience :)
User avatar
Masonjar13
Posts: 1403
Joined: 20 Jul 2014, 10:16
GitHub: Masonjar13
Location: Не Россия

Re: AHKathon! [AHK Hackathon] 12/17

20 Jan 2018, 16:47

Finally, we have scores! :dance: (Note: scale is 1-7, and "Performance" was nulled out.)

3rd: jeeswg - 4.5

2nd: Micromegas - 5.1

1st: Helgef - 6.1

Congratulations, and thanks to everyone who participated! I did make some notes regarding each entry (not very nit-picky since there were few entries); if you'd like to read them, as well as your score breakdown, please PM me! :) I will be PM'ing the 3 winners with confirmation of accepting and choosing of game keys, or lack thereof.

Concerning future AHKathons
I'd like to gather a small group of judges for future AHKathons. Note that judges may not participate, or at the very least, may not be considered for any prizes. Alternatively, we could have an open (community) vote. Or both! In which case the judges would narrow down the entries, then the community would decide winners.. or vice-versa. Please voice your opinions on this, either here in the thread or you may PM me, including if you'd like to be a judge, I'd really appreciate it!

Return to “Offtopic”

Who is online

Users browsing this forum: No registered users and 18 guests