Skip to content

Instantly share code, notes, and snippets.

@KarlRamstedt
Last active August 13, 2024 15:16
Show Gist options
  • Save KarlRamstedt/70865b52f85f1d3ec42424c92e866401 to your computer and use it in GitHub Desktop.
Save KarlRamstedt/70865b52f85f1d3ec42424c92e866401 to your computer and use it in GitHub Desktop.
AHK Crosshair Overlay
#NoEnv ; For performance and compatibility with future AutoHotkey releases
Gui, -Caption +AlwaysOnTop +ToolWindow +LastFound +E0x20 ; +E0x20 makes the window click-through
Gui, Margin, 0, 0 ; Remove margins to get perfect alignment with center of screen
Gui, Add, Picture, , Crosshair.png ; Picture file name, in the same folder as the script
Controlgetpos, , , picW, picH, , ; Store picture width and height in variables
xPos := A_ScreenWidth/2 - picW/2
yPos := A_ScreenHeight/2 - picH/2 ; Used to align picture center with screen center
Gui, Show, x%xPos% y%yPos% NA ; Crosshair can be moved by manually setting X and Y numbers
Gui, Color, 0000FF ; Set background color. You might need to change this color to one not contained in the crosshair
WinSet, TransColor, 0000FF ; Make the background color transparent
; Uses a GDI+ Library made by tic (Tariq Porter). Download it here(required): ahkscript.org/boards/viewtopic.php?t=6517
; Requires Gdip.ahk either in your Lib folder as standard library or using #Include
#Include, Gdip.ahk
#NoEnv ; For performance and compatibility with future AutoHotkey releases
If !pToken := Gdip_Startup(){
MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
ExitApp
}
OnExit, Exit
Gui, -Caption +AlwaysOnTop +ToolWindow +LastFound +OwnDialogs +E0x80000 +HwndCHhwnd +E0x20 ; Create layered window (+E0x80000 is required for UpdateLayeredWindow). +HwndName creates a variable with a name of your choice, containing the Hwnd of the window. +E0x20 makes the window click-through
Gui, Show, NA ; Show window without activating it
pBitmap := Gdip_CreateBitmapFromFile("Crosshair.png") ; Get bitmap from the image
If !pBitmap { ; Ensure we actually got a bitmap from the file, in case the file was corrupt or other error
MsgBox, 48, File loading error!, Could not load 'Crosshair.png'
ExitApp
}
width := Gdip_GetImagewidth(pBitmap), height := Gdip_GetImageheight(pBitmap)
hbm := CreateDIBSection(width, height) ; Create a gdi bitmap with width and height of what we are going to draw into it. This is the drawing area for everything
hdc := CreateCompatibleDC() ; Get a device context compatible with the screen
obm := SelectObject(hdc, hbm) ; Select the bitmap into the device context
gPointer := Gdip_GraphicsFromHDC(hdc) ; Get a pointer to the bitmap graphics
; DrawImage draws the bitmap we took from the file into the graphics of the bitmap we created
; Gdip_DrawImage(pGraphics, pBitmap, dx, dy, dw, dh, sx, sy, sw, sh, Matrix) d = destination and s = source. The matrix is for changing colours when drawing
Gdip_DrawImage(gPointer, pBitmap, 0, 0, width, height, 0, 0, width, height)
; Update the window(CHhwnd) with a handle to our bitmap (hdc), specifying screen coordinates and size (x,y,w,h)
; A_Screenwidth/2-width/2 aligns the center of the image with the center of your screen
UpdateLayeredWindow(CHhwnd, hdc, A_Screenwidth/2-width/2, A_Screenheight/2-height/2, width, height)
SelectObject(hdc, obm) ; Select the object back into the hdc
DeleteObject(hbm) ; The bitmap may now be deleted
DeleteDC(hdc) ; The device context related to the bitmap may be deleted
Gdip_DeleteGraphics(gPointer) ; The graphics may now be deleted
Gdip_DisposeImage(pBitmap) ; The bitmap we made from the image may be deleted
return
Exit:
Gdip_Shutdown(pToken)
ExitApp
return
@KarlRamstedt
Copy link
Author

KarlRamstedt commented May 29, 2020

Both scripts basically find an image with the name Crosshair.png in the same folder as the script and render it on top of all your Windows.

The first script is simpler and doesn't require an external library, but can't handle partial transparency (i.e: either full transparency or none) and might require you to change transparency color, depending on your crosshair color (by default Blue is treated as transparent).
The second script uses GDI+ to render partial transparency and doesn't need any changes regardless of crosshair color. GDI+ can be found here (put the script in the same folder).
Overall, I'd recommend using the second version if you can get it working.

Any .png image can be used as a crosshair. Just have fun with your image editor. I recommend Green or White for crosshair color due to the nature of RGB pixel-structures in modern screens.
Note: Make sure your crosshair image dimensions are divisible by 2, otherwise it won't be perfectly centered, because the number of pixels in standard resolutions are divisible by 2 in both the vertical and horizontal axis.

@KarlRamstedt
Copy link
Author

KarlRamstedt commented May 29, 2020

To add a toggle for enabling/disabling the crosshair, add this code to the end of the script (works with both scripts):

global showCrosshair := true

<^>!I:: ; AltGr+I to toggle crosshair
	showCrosshair := !showCrosshair
	if (showCrosshair)
		Gui, Show, NA ; Show window without activating it
	else
		Gui, Show, hide
return

@orlp
Copy link

orlp commented Aug 29, 2022

It's almost perfect, I would just change the following line:

Gui, -Caption +AlwaysOnTop +ToolWindow +LastFound +OwnDialogs +E0x80000 +HwndCHhwnd

If we add +E0x20 the crosshair becomes click-through!

Gui, -Caption +AlwaysOnTop +ToolWindow +LastFound +OwnDialogs +E0x80000 +HwndCHhwnd +E0x20

@Jusp3
Copy link

Jusp3 commented Jul 29, 2023

I made it to detect the game with these additions and its toggles off automatically when alt tabbing or closing game.

SetTimer, process1check, 1000
process1check:
IfWinActive, ahk_exe RustClient.exe
		Gui, Show, NA ; Show window without activating it
	else
		Gui, Show, hide
return

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment