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-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".