"scaw" - an onscreen modifier key toggle

Post your working scripts, libraries and tools for AHK v1.1 and older
SundayProgrammer
Posts: 143
Joined: 25 Dec 2020, 12:26

"scaw" - an onscreen modifier key toggle

Post by SundayProgrammer » 24 Jan 2022, 20:07

Code: Select all

If A_Args.Length()
	Param1 = %1%
If not RegExMatch(Param1, "i)S|C|A|W")
	ExitApp
OnMessage(0x204, "WM_RBUTTONDOWN")
nm := {"S":"Shift", "C":"Ctrl", "A":"Alt", "W":"Win"}, xp := {"S":34, "C":31, "A":33, "W":33}, ps := {}, Pos := {}
For k, v in nm
	If InStr(Param1, k)
		CreateGui(k, v, xp[k])
SetTimer, UpdateGui, 500
Return
SCAW_begLoc(ca) {
	If ca = S
		Return "y" A_ScreenHeight / 2 + 20
	Else If ca = C
		Return "x" A_ScreenWidth / 2 + 20 " y" A_ScreenHeight / 2 - 55
	Else If ca = A
		Return "y" A_ScreenHeight / 2 - 130
	Else If ca = W
		Return "x" A_ScreenWidth / 2 - 130 " y" A_ScreenHeight / 2 - 55
}

CreateGui(ca, ac, x) {
	global ps, Pos
	ps[ca] := GetTheState(ac)
	Gui, %ca%:New, +LastFound -Caption +AlwaysOnTop +ToolWindow
	Gui, Color, White
	Gui, Margin, 0, 0
	Gui, Font, s70 cB2D6F3, Consolas
	Gui, Add, Text, x0 y0 BackgroundTrans gHit, 🛑
	Gui, Font, s60 cRed bold, Consolas
	Gui, Add, Text, x%x% y10 BackgroundTrans gHit, %ca%
	WinSet, TransColor, White 64
	xy := SCAW_begLoc(ca)
	Gui, Show, %xy% NoActivate, %ac% State Toggle
	WinGetPos, x, y,,, %ac% State Toggle
	Pos[ca] := x "," y
	Toggle(ac, ps[ca])
}
WM_RBUTTONDOWN(wParam, lParam, msg, hwnd) {
	global Pos
	MouseGetPos, x, y, w
	While, GetKeyState("RBUTTON", "P")
	{	MouseGetPos, xx, yy
		If moved := (Abs(xx - x) > 10 or Abs(yy - y) > 10)
			Break
	}If moved or lParam = 12345
	{	If lParam = 12345
			w := wParam
		x := SubStr(Pos[A_Gui], 1, (p := InStr(Pos[A_Gui], ",")) - 1)
		If Abs(x * 2 + 110 - A_ScreenWidth) < 25
		{	y := SubStr(Pos[A_Gui], p + 1)
			If Abs(y * 2 + 110 - A_ScreenHeight) < 25
			{	WinMove, ahk_id %w%,, (xx := (x - 50))
				Pos[A_Gui] := xx SubStr(Pos[A_Gui], p)
			}Else
			{	WinMove, ahk_id %w%,,, (yy := (A_ScreenHeight - 110) - y)
				Pos[A_Gui] := x "," yy
			}
		}Else
		{	WinMove, ahk_id %w%,, (xx := (A_ScreenWidth - 110) - x)
			Pos[A_Gui] := xx SubStr(Pos[A_Gui], p)
		}
	}Else ExitApp
}
Hit(hwnd) {
	global Pos
	SendMessage, 0xA1, 2,,, A	; WM_NCLBUTTONDOWN
	GuiControlGet, wHwnd, Hwnd, %hwnd%
	WinGetPos, x, y,,, ahk_id %wHwnd%
	If x "," y = Pos[A_Gui]
		UpdateGui(True)
	Else Pos[A_Gui] := x "," y
	Gui, %A_Gui%:Hide
	Gui, %A_Gui%:Show, NoActivate
}
UpdateGui(FromHit := False) {
	global nm, ps
	If FromHit
	{	color := Toggle(nm[A_Gui], GetTheState(nm[A_Gui]))
		Gui, Font, s60 c%color% bold, Consolas
		GuiControl, Font, Static2
		ps[A_Gui] := GetTheState(nm[A_Gui])
	}Else
For k, v in nm
	If not ((currentState := GetTheState(v)) = ps[k])
	{	color := currentState ? "Red" : "Blue"
		Gui, %k%:Font, s60 c%color% bold, Consolas
		GuiControl, %k%:Font, Static2
		ps[k] := currentState
	}
}
GetTheState(ac) {
	If ac = Win
		Return GetKeyState("LWin", "P") or GetKeyState("RWin", "P")
	Else Return GetKeyState(ac, "P")
}
Toggle(ac, currentState) {
	If ac = Win
		ac := "LWin"
	st := currentState ? "Up" : "Down"
	Send, {%ac% %st%}
	Return currentState ? "Blue" : "Red"
}

it requires one command line parameter (or you may implant the "param1" variable instead though (see my examples)).

if the parameter contains "s", the "shift" toggle will be created; and likewise, if the parameter contains "c", the "ctrl" toggle will be created; and likewise, if the parameter contains "a", the "alt" toggle will be created; and likewise, if the parameter contains "w", the "win" toggle will be created. the parameter can contain any combinations of these four letters.

use right click to dismiss the toggle(s), i.e. exitapp. and right-drag to flick it to the other side (left/right).

it turns red if its current state is "down" whereas it's in blue when its current state is "up". it tracks the state(s) every 500ms and update the gui(s) accordingly, thus it can reflect the most current state(s) even if the modifiers states are altered by some other means.

it's movable. it's semi-transparent. it's touch friendly.

in case you want to use it from spotmenu (viewtopic.php?p=440618#p440618), try these examples below. (assumed you saved the script above as mktoggle.ahk)

Code: Select all

C.toggle	{Ctrl State Toggle}	(Script)
S.toggle	{Shift State Toggle}	(Script)
SC.toggle	{Shift & Ctrl State Toggles}	(Script)
;
{Script Ctrl State Toggle}
	Param1 = Ctrl
	#Include, mkToggle.ahk
{/Script}

{Script Shift State Toggle}
	Param1 = Shift
	#Include, mkToggle.ahk
{/Script}

{Script Shift & Ctrl State Toggles}
	Param1 = Shift & Ctrl
	#Include, mkToggle.ahk
{/Script}
2022-01-25 edited: made some cosmetic (merely) adjustments to the script.
2022-01-26 edited: another adjustment (kinda cosmetic) which detects if it's currently at the middle of the screen, and to have "flick" worked one way or the other. so that there will be no cases it doesn't move (nor just moved a micro) after "flick".

Return to “Scripts and Functions (v1)”