- The script is an AHK v2 script, rather than an AHK v1.1 script, because AHK v2 is much better for producing GUIs.
Code: Select all
;AHK v2
;Find dialog with whole word and RegEx support
;note: alt+down to display the drop-down list
#SingleInstance force
#KeyHistory 0
#UseHook
ListLines("Off")
A_TrayMenu.ClickCount := 1
#Persistent
;#NoTrayIcon
DetectHiddenWindows("On")
SplitPath(A_ScriptName,,,, vScriptNameNoExt)
A_IconTip := vScriptNameNoExt
;options:
;set the Find dialog window size:
;vZoom := 1.8
vZoom := 1.5
;in a 'whole' match, characters not considered boundary characters:
vCharList := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
;shift+enter to search upwards:
vDoShiftEnter := 1
;when do search, hide box or maintain box:
vDoHideWhenSearch := 0
;if needle not found, move caret to start/end and retry:
vDoRetry := 1
;determine target window
GroupAdd("WinGroupFind", "ahk_class Notepad")
vNeedle := ""
vWhole := 0
vCaseSen := 0
vUp := 0
vDown := 1
;==================================================
;WINDOW=X0 Y0 W354 H121 ;originally: H101
vList := " ;continuation section
(C
Text=X6 Y13 W63 H13
Edit=X71 Y11 W192 H20
Checkbox=X6 Y42 W150 H20
Checkbox=X6 Y68 W96 H20
GroupBox=X161 Y42 W102 H46
Radio=X167 Y62 W38 H20
Radio=X207 Y62 W53 H20
Button=X273 Y8 W75 H23
Button=X273 Y37 W75 H23
Button=X273 Y73 W75 H23
Checkbox=X6 Y94 W150 H20 ;I added this control
)"
vList := RegExReplace(vList, "`am)[XYWH](?!.*=)")
oPos := []
Loop Parse, vList, "`n"
{
oTemp := StrSplit(A_LoopField, ["=", " "])
oTemp.RemoveAt(1)
Loop 4
oTemp[A_Index] *= vZoom
vCtlPos := Format("X{} Y{} W{} H{}", oTemp*)
oPos.Push(vCtlPos)
}
oGui := GuiCreate("-MinimizeBox", "Find")
hGui := oGui.hWnd
oGui.OnEvent("Close", "Gui_Close")
oGui.OnEvent("Escape", "OnCancel")
oGui.SetFont("s18", "Arial")
;12 controls: Static, ComboBox+Edit, 9 Buttons
;BS_MULTILINE := 0x2000
;WS_EX_NOPARENTNOTIFY := 0x4
oGui.Add("Text", oPos.1 " +E0x4 +Group", "Fi&nd what:")
oCbx := oGui.Add("ComboBox", oPos.2 " +E0x4 +Group R8")
hCbx := oCbx.hWnd
hEdit := ControlGetHwnd("Edit1", "ahk_id " hCbx)
oEdit := GuiCtrlFromHwnd(hEdit)
oBtnW := oGui.Add("Checkbox", oPos.3 " -0x2000 +E0x4 +Group", "Match &whole word only")
oBtnC := oGui.Add("Checkbox", oPos.4 " -0x2000 +E0x4", "Match &case")
oBtnG := oGui.Add("GroupBox", oPos.5 " -0x2000 +E0x4 +Group", "Direction")
oBtnU := oGui.Add("Radio", oPos.6 " -0x2000 +E0x4 +Group", "&Up")
oBtnD := oGui.Add("Radio", oPos.7 " -0x2000 +E0x4 +Checked", "&Down")
oBtnF := oGui.Add("Button", oPos.8 " -0x2000 +E0x4 +Group", "&Find Next")
oBtnX := oGui.Add("Button", oPos.9 " -0x2000 +E0x4", "Cancel")
oBtnH := oGui.Add("Button", oPos.10 " -0x2000 +E0x4 +Hidden +Disabled", "&Help")
oBtnR := oGui.Add("Checkbox", oPos.11 " -0x2000 +E0x4", "Match &RegEx")
oBtnF.OnEvent("Click", "OnSearch")
oBtnR.OnEvent("Click", "OnCheckRegEx")
oBtnW.OnEvent("Click", "OnCheckWhole")
oBtnX.OnEvent("Click", "OnCancel")
oBtnF.Opt("+Default")
;note: oBtnG/oBtnH/hBtnG/hBtnH not used by script
Loop Parse, "CDFGHRUWX"
hBtn%A_LoopField% := oBtn%A_LoopField%.hWnd
;remove menu items (Restore/Size/Minimize/Maximize/separator):
;keep only Move/Close menu items
;SC_RESTORE := 0xF120 ;SC_MOVE := 0xF010
;SC_SIZE := 0xF000 ;SC_MINIMIZE := 0xF020
;SC_MAXIMIZE := 0xF030 ;SC_CLOSE := 0xF060
hSysMenu := DllCall("GetSystemMenu", Ptr,hGui, Int,0, Ptr)
vList := "0xF120,0xF000,0xF020,0xF030"
Loop Parse, vList, ","
DllCall("user32\RemoveMenu", Ptr,hSysMenu, UInt,A_LoopField, UInt,0x0)
DllCall("user32\RemoveMenu", Ptr,hSysMenu, UInt,1, UInt,0x400) ;MF_BYPOSITION := 0x400 ;remove separator
OnMessage(0x100, "OnKeyDown") ;WM_KEYDOWN := 0x100
oSearchHist := []
return
;==================================================
#If WinActive("ahk_group WinGroupFind")
^f:: ;show Find dialog
hWndMain := WinGetID("ahk_group WinGroupFind")
if JEE_WinIsVisible(hGui)
{
WinActivate("ahk_id " hGui)
hWndMainLast := hWndMain
return
}
if !(hWndMainLast = hWndMain)
{
;check Down, uncheck Up
PostMessage(0xF1, 1, 0,, "ahk_id " hBtnD) ;BM_SETCHECK := 0xF1
PostMessage(0xF1, 0, 0,, "ahk_id " hBtnU) ;BM_SETCHECK := 0xF1
}
ControlFocus("Edit1", "ahk_id " hGui)
PostMessage(0xB1, 0, -1,, "ahk_id " hEdit) ;EM_SETSEL := 0xB1 ;select all
;WinActivate("ahk_id " hGui)
;WinShow("ahk_id " hGui)
;oGui.Show()
;oGui.Show("X202 Y283")
oGui.Show("X202 Y325")
hWndMainLast := hWndMain
return
;==================================================
F3:: ;repeat last search
hWndMain2 := WinGetID("ahk_group WinGroupFind")
hCtlMain2 := ControlGetHwnd("Edit1", "ahk_id " hWndMain2)
if vDoHideWhenSearch
{
oGui.Hide()
WinActivate("ahk_id " hWndMain2)
ControlFocus(, "ahk_id " hCtlMain2)
}
vNeedle := ControlGetText(, "ahk_id " hEdit)
if (vNeedle = "")
return
vWhole := ControlGetChecked(, "ahk_id " hBtnW)
vCaseSen := ControlGetChecked(, "ahk_id " hBtnC)
;vUp := ControlGetChecked(, "ahk_id " hBtnU)
vDown := ControlGetChecked(, "ahk_id " hBtnD)
vRegEx := ControlGetChecked(, "ahk_id " hBtnR)
vNormal := !vWhole && !vRegEx
;note: repeated options e.g. 'ii)' are permitted
if vRegEx
if vCaseSen
vNeedle2 := vNeedle
else if RegExMatch(vNeedle, "^[A-Za-z`a`n`r `t]*\K\)")
vNeedle2 := "i" vNeedle
else
vNeedle2 := "i)" vNeedle
if vIsRetry
vPos1 := vPos2 := vDown ? 0 : vLen, vIsRetry := 0
else
JEE_EditGetSel(hCtlMain2, vPos1, vPos2)
vPos1 += 2 ;convert to 1-based, add 1, so +1+1
vPos2 -= 1 ;convert to 1-based, subtract 2, so +1-2
vText := ControlGetText(, "ahk_id " hCtlMain2)
vLen := StrLen(vText)
vLenN := StrLen(vNeedle)
if (vNormal || vWhole) && (vLenN > vLen)
return
vPos := ""
if vNormal && vDown
vPos := InStr(vText, vNeedle, vCaseSen, vPos1)
else if vNormal && !vDown
vPos := InStr(vText, vNeedle, vCaseSen, vPos2-vLen-1) ;AHK v2: -1 = len-len-1 = last char
else if vWhole && vDown
vPos := JEE_InStrWhole(vText, vNeedle, vCaseSen, vPos1, 1, vCharList)
else if vWhole && !vDown
vPos := JEE_InStrWhole(vText, vNeedle, vCaseSen, vPos2-vLen-1, 1, vCharList)
else if vRegEx && vDown
try vPos := JEE_RegExMatch(vText, vNeedle2, oMatch, vPos1)
else if vRegEx && !vDown
try vPos := JEE_RegExMatchLast(SubStr(vText, 1, vPos1-1), vNeedle2, oMatch)
if vRegEx && (vPos = "")
{
MsgBox("error: invalid RegEx")
return
}
if vPos
{
vLenN := vRegEx ? StrLen(oMatch.0) : StrLen(vNeedle)
WinActivate("ahk_id " hWndMain2)
SendMessage(0xB1, vPos-1, vPos-1+vLenN,, "ahk_id " hCtlMain2) ;EM_SETSEL := 0xB1
PostMessage(0xB7, 0, 0,, "ahk_id " hCtlMain2) ;EM_SCROLLCARET := 0xB7
if !InStr(A_ThisHotkey, "F3")
&& !vDoHideWhenSearch
WinActivate("ahk_id " hGui)
}
else if !vDoRetry
MsgBox("text not found:`r`n" vNeedle)
else
{
vRet := MsgBox("start again from " (vDown ? "top" : "bottom") " of file?",, "YNC")
if (vRet = "Yes")
{
vIsRetry := 1
Gosub F3
}
else
oGui.Hide()
}
return
;==================================================
;JEE_WinVisible
;JEE_WinGetVisible
JEE_WinIsVisible(hWnd)
{
if DllCall("user32\IsWindowVisible", Ptr,hWnd) ;1 = visible, 0 = not visible
return 1
else
return 0
}
;==================================================
;where vPos1 and vPos2 are 0-based
;e.g. JEE_EditGetSel(hCtl, vPos1, vPos2)
;vPos1=left, vPos2=right
;JEE_EditGetRange
JEE_EditGetSel(hCtl, ByRef vPos1, ByRef vPos2)
{
VarSetCapacity(vPos1, 4, 0), VarSetCapacity(vPos2, 4, 0)
SendMessage(0xB0, &vPos1, &vPos2,, "ahk_id " hCtl) ;EM_GETSEL := 0xB0 ;(left, right)
vPos1 := NumGet(&vPos1, 0, "UInt"), vPos2 := NumGet(&vPos2, 0, "UInt")
}
;==================================================
;where vPos1 and vPos2 are 0-based
;e.g. JEE_EditSetSel(hCtl, vPos1, vPos2)
;vPos1=anchor, vPos2=active
;JEE_EditSetRange
JEE_EditSetSel(hCtl, vPos1, vPos2, vDoScroll:=0)
{
SendMessage(0xB1, vPos1, vPos2,, "ahk_id " hCtl) ;EM_SETSEL := 0xB1 ;(anchor, active)
if vDoScroll
SendMessage(0xB7, 0, 0,, "ahk_id " hCtl) ;EM_SCROLLCARET := 0xB7
}
;==================================================
OnCancel()
{
global hGui
WinHide("ahk_id " hGui)
}
OnCheckRegEx()
{
global hBtnW
;note: RegEx is toggled automatically
;uncheck Whole
PostMessage(0xF1, 0, 0,, "ahk_id " hBtnW) ;BM_SETCHECK := 0xF1
}
OnCheckWhole()
{
global hBtnR,
;note: Whole is toggled automatically
;uncheck RegEx
PostMessage(0xF1, 0, 0,, "ahk_id " hBtnR) ;BM_SETCHECK := 0xF1
}
;Ctrl+F: prevent beep, focus Edit control
;Shift+Enter: search upwards
OnKeyDown(wParam, lParam, uMsg, hWnd) ;WM_KEYDOWN := 0x100
{
global hBtnD, hBtnU, hEdit, hGui, vDoShiftEnter
if (wParam = 0x46) ;F
&& !GetKeyState("Shift")
&& GetKeyState("Ctrl")
&& !GetKeyState("LWin")
&& !GetKeyState("RWin")
&& !GetKeyState("Alt")
{
WinActivate("ahk_id " hGui)
ControlFocus(, "ahk_id " hEdit)
return 0
}
if vDoShiftEnter
&& (wParam = 0xD) ;VK_RETURN := 0xD ;Enter
&& GetKeyState("Shift")
&& !GetKeyState("Ctrl")
&& !GetKeyState("LWin")
&& !GetKeyState("RWin")
&& !GetKeyState("Alt")
{
;check Up, uncheck Down
SendMessage(0xF1, 1, 0,, "ahk_id " hBtnU) ;BM_SETCHECK := 0xF1
PostMessage(0xF1, 0, 0,, "ahk_id " hBtnD) ;BM_SETCHECK := 0xF1
Gosub F3
return 0
}
}
OnSearch()
{
global hCbx, oCbx, oSearchHist
;vNeedle := ControlGetText(, "ahk_id " hCbx)
vNeedle := oCbx.Text
if (vNeedle = "")
return
for vKey, vValue in oSearchHist
if (vValue = vNeedle)
{
vKeyDel := vKey
break
}
if !(vKeyDel = "")
oSearchHist.RemoveAt(vKeyDel)
oSearchHist.InsertAt(1, vNeedle)
oCbx.Delete()
oCbx.Add(oSearchHist)
oCbx.Value := 1
Gosub F3
}
Gui_Close()
{
;ExitApp()
}
;==================================================
JEE_InStrWhole(vText, vNeedle, vCaseSen:=0, vPos:=1, vOcc:=1, vCharList:="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
{
static vIsV1 := !!InStr(1, 1, 1, 0)
if (vPos = 0)
return
if vIsV1 && (vPos <= -1)
vPos++
if (vPos > 1)
while vPos := InStr(vText, vNeedle, vCaseSen, vPos)
{
vChar2 := SubStr(vText, vPos+StrLen(vNeedle), 1)
if ((vPos = 1) || !InStr(vCharList, SubStr(vText, vPos-1, 1)))
&& ((vChar2 = "") || !InStr(vCharList, vChar2))
return vPos
vPos++
}
else ;handle negative offset
while vPos := InStr(vText, vNeedle, vCaseSen, vPos)
{
vChar2 := SubStr(vText, vPos+StrLen(vNeedle), 1)
if ((vPos = 1) || !InStr(vCharList, SubStr(vText, vPos-1, 1)))
&& ((vChar2 = "") || !InStr(vCharList, vChar2))
return vPos
vPos++
}
return 0
}
;==================================================
;MsgBox, % JEE_RegExMatchLast("aaaaaaaaaabbbbb", "a") ;10
;MsgBox, % JEE_RegExMatchLast("a`r`na`r`na", "a") ;7
;MsgBox, % JEE_RegExMatchLast("a`ra`ra", "a") ;5
;MsgBox, % JEE_RegExMatchLast("a`na`na", "a") ;5
;works like RegExMatch (AHK v2) (on AHK v1/v2)
JEE_RegExMatchLast(ByRef vText, vNeedle, ByRef oArray:="", vPos:=1)
{
if vPosX := RegExMatch(vNeedle, "^[A-Za-z`a`n`r `t]*\K\)")
vOpt := SubStr(vNeedle, 1, vPosX-1), vNeedle := SubStr(vNeedle, vPosX+1)
if !InStr(vOpt, "s", 1)
vOpt := "s" vOpt
return JEE_RegExMatch(vText, (vOpt = "" ? "" : vOpt ")") ".*\K" vNeedle, oArray, vPos)
}
;==================================================
;works like RegExMatch (AHK v2) (on AHK v1/v2)
JEE_RegExMatch(ByRef vText, vNeedle, ByRef oArray:="", vPos:=1)
{
;we're not interested in the return value, but we need it to get RegExMatch to take place
static vRet := RegExMatch("", "", o), vIsV1 := !IsObject(o)
if !vIsV1
return RegExMatch(vText, vNeedle, oArray, vPos)
if (vPos = 0)
return
else if (vPos <= -1)
vPos++
if vPosX := RegExMatch(vNeedle, "^[A-Za-z`a`n`r `t]*\K\)")
vOpt := "O" SubStr(vNeedle, 1, vPosX-1), vNeedle := SubStr(vNeedle, vPosX+1)
else
vOpt := "O"
if !RegExMatch(vOpt, "[`r`n`a]")
vNeedle := "(*ANYCRLF)(*BSR_ANYCRLF)" vNeedle
return RegExMatch(vText, vOpt ")" vNeedle, oArray, vPos)
}
;==================================================