This repository has been archived by the owner on Jan 9, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathXYAHKLiveFilter.ahk
330 lines (307 loc) · 12.6 KB
/
XYAHKLiveFilter.ahk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
;XYAHKLiveFilter.ahk/v5.0.1b/author:SammaySarkar
;http://xyplorer.com/xyfc/viewtopic.php?t=12588
;https://github.com/smsrkr/XYAHKLiveFilter
#SingleInstance, Off ;multiple instances can run for multiple XY instances
;#NoTrayIcon ;hide tray icon
#NoEnv ;(recommended)
SetBatchLines, 10ms ;good balance of speed/CPU (so says AHK doc)
SetControlDelay, -1 ;fastest possible control operations
Global AHKhWnd := A_ScriptHwnd + 0 ;own hwnd in base10, can pass to SC copydata
Global ReceivedData, ActionData ;holds WM_COPYDATA returns
Global GUIhWnd ;holds gui hwnd
Global GUIEdithWnd,GUIPausehWnd ;holds gui elements hwnd
Global XYhWnd ;parent/target XY window hwnd
Global dwDataMode ;dwData possible values sent from XY
dwDataMode := [4194304,4194305,4194306] ;corresp. modes 0,1,2
;data sent in mode 0 is utilized in normal progran flow
;data sent in mode 1 triggers actions like focus/quit etc based on data
;process XY hwnd from cmdline
XYhWnd = %1%
XYhWnd := Format("0x{:x}", XYhWnd) ;convert to hex, like GUIhWnd
;retrieve other options from cmdline
Shortcut = %2% ;hotkey to focus filterbox
ABPadding = %3% ;manual adjustent of GUI Y (for same Y of AB)
ABPadding := (ABPadding+0 == "") ? 5 : ABPadding
SyncPos = %4% ;sync GUI position with AB (else at the topleft of XY)
OwnCTB = %5% ;ID of associated custom toolbar button in XY (>= 0)
Quote = %6% ;Pattern quoting; S or D: single-quotes or double
;validate Quote
If Quote in S,D,s,d
Quote := Quote
Else
Quote := "S"
Quote := (Quote = "S") ? "'" : """" ;single '=' case-insensitive compare
;setup event hooks
OnExit, ExitRoutine ;need to cleanup before exit
OnMessage(0x4a, "MsgFromXY") ;WM_COPYDATA
OnMessage(0x02, "Destroyer") ;WM_DESTROY
;OnMessage(0x200, "FocusGUI") ;WM_MOUSEMOVE | disabled, non-standard
;store own HWND in 2nd var as <xyHwnd> <ownHwnd>
MsgToXY("::perm $p_XYAHKLiveFilter_B = $p_XYAHKLiveFilter_B.' '." AHKhWnd ";")
;get current VF/GVF
MsgToXY("::copydata " AHKhWnd ",get('visualfilter'),0;")
CurrVF := ReceivedData
;setup GUI
Gui, +HwndGUIhWnd -Border -Caption +OwnDialogs +AlwaysOnTop
Gui, Margin, 2, 1
GoSub, Sysdims ;get some system element dims for correct positioning
If (SyncPos == 1) ;right-align with AB
GoSub, ABdims ;get AB position
Else ;else right-align with window
GoSub, Windims ;get window position
Gui, Font, s%FontSize%, %FontName%
GUI, Add, Checkbox, gCallUpdateFilter hWndGUIPausehWnd 0xc00, P ;pause checkbox
Gui, Add, Edit, y1 hWndGUIEdithWnd R1, %A_Space% ;filterbox, " " for sizing
;set as child of XY
DllCall("SetParent", "Ptr", GUIhWnd, "Ptr", XYhWnd, "Ptr")
GuiControlGet, EditPos, Pos, %GUIEdithWnd%
GuiControl, Move, %GUIEdithWnd%, % "w" EditPosW*12 ;set a sane width
GuiControl, Move, %GUIPausehWnd%, % "h" EditPosH ;chkbox H==edit H
GuiControl,, %GUIEdithWnd%, %CurrVF% ;remove default " " content
GuiControl, +gCallUpdateFilter, %GUIEdithWnd% ;add label after setting text
GuiControl, Focus, %GUIEdithWnd% ;focus filterbox
Gui, Show, X%GUIX% Y%GUIY% AutoSize
;setup position
WinGetPos,,, GUIW,, ahk_id %GUIhWnd% ;get current width
If (SyncPos == 1) { ;right align filterbox with AB
GUIX := AncX + AncW - xborder - GUIW ;get real abwidth - GUIWidth
SetTimer, UpdatePosAB, 100 ;turn on the position synchronizer
}
Else {
GUIX := AncW - xborder*2 - GUIW ;get real winwidth - GUIWidth
SetTimer, UpdatePosWin, 100 ;turn on the position synchronizer
}
WinMove, ahk_id %GUIhWnd%,, %GUIX%, %GUIY% ;set new position
;setup hotkeys
If (Shortcut) { ;put this first to override any other
Hotkey, IfWinActive, ahk_id %XYhWnd% ;trigger only when parent XY active
Hotkey, %Shortcut%, lblFocusGUI ;hotkey to refocus filterbox
}
Hotkey, IfWinActive, ahk_id %GUIhWnd%
Hotkey, Tab, lblFocusXY ;tab to give focus to XY
Hotkey, Enter, UpdateFilter ;ENTER to force filter update
Hotkey, !p, lblTogglePause ;alt+p to toggle pause status
;and Escape key closes GUI via GuiEscape label
Return
;=== END OF AUTO-EXECUTION SECTION =============================================
;obtain necessary AddressBar attributes
ABdims:
;ensure AB is visible
MsgToXy("::copydata " AHKhWnd ",get('#660'),0;setlayout('showaddressbar=1');")
;^get(#660) AB visibility (returns 1||0)
ABState := ReceivedData ;remember prev AB visibility to revert back
ReceivedData := "" ;reset receiveddata
;infer AB position relative to clientarea (thanks, autocart :) )
ControlGet, XYABhWnd, Hwnd,, Edit16, ahk_id %XYhWnd%
ControlGetPos, AncX, AncY, AncW, AncH,, ahk_id %XYABhWnd%
GUIX := AncX + AncW - xborder ;GUIWidth is accounted for after GUI,Show
GUIY := AncY - yborder - CaptionH - MenuH - ABPadding
FontName := GetFont(XYABhWnd) ;get fontname of AB
FontSize := A_LastError ;get fontsize of AB
Return
;obtain necessary XY Window attributes
Windims:
WinGetPos,,, AncW,, ahk_id %XYhWnd%
GUIX := AncW - xborder*2 ;GUIWidth is accounted for after GUI,Show
GUIY := 1 ;no need for dynamic Y pos
FontName := GetFont(XYhWnd) ;get fontname of win
FontSize := A_LastError ;get fontsize of win
Return
;obtain some system dimension attributes
Sysdims:
SysGet, CaptionH, 4
SysGet, MenuH, 15
SysGet, xborder, 32
SysGet, yborder, 33
Return
;update filterbox position to match AB. Called by timer
UpdatePosAB:
If WinActive("ahk_id" XYhWnd) { ;update position only while XY is active
ControlGet, ABvis, Visible,,, ahk_id %XYABhWnd% ;get AB visiblity
If (ABvis == 0) ;if AB is hidden
MsgToXY("::setlayout('showaddressbar=1')") ;unhide AB while running
PAncA = %AncX% %AncY% %AncH% %AncW% ;previous AB dims
PAncB = %AncH% ;previous AB H
ControlGetPos, AncX, AncY, AncW, AncH,, ahk_id %XYABhWnd%
CAncA = %AncX% %AncY% %AncH% %AncW% ;current AB dims
CAncB = %AncH% ;current AB H
If (PAncA != CAncA) { ;AB pos change = sync new pos
GUIX := AncX + AncW - xborder - GUIW
GUIY := AncY - yborder - CaptionH - MenuH - ABPadding
GUIH := AncH + ABPadding
If (PAncB <> CAncB) { ;AB H change = font change
FontName := GetFont(XYABhWnd) ;get new fontname
FontSize := A_LastError ;get new fontsize
Gui, Font, s%FontSize%, %FontName% ;set new font
GuiControl, Font, %GUIPausehWnd% ;apply font to P chkbox
GuiControl, Font, %GUIEdithWnd% ;and to filterbox
}
WinMove, ahk_id %GUIhWnd%,, %GUIX%, %GUIY%,, %GUIH% ;set new position
GuiControl, move, %GUIPausehWnd%, h%GUIH% ;pause H = GUI H
GuiControl, move, %GUIEdithWnd%, h%GUIH% ;filterH - GUI H
}
}
Return
;update filterbox position to match Window. Called by timer
UpdatePosWin:
If WinActive("ahk_id" XYhWnd) { ;update position only while XY is active
PAncA = %AncW% ;previous win W
WinGetPos,,, AncW,, ahk_id %XYhWnd%
CAncA = %AncW% ;current win W
If (PAncA != CAncA) { ;Win W change = sync new pos
GUIX := AncW - xborder*2 - GUIW
GUIY := 1
WinMove, ahk_id %GUIhWnd%,, %GUIX%, %GUIY% ;set new position
}
}
Return
;toggle between VF and GVF
SwitchGVF:
Return
;triggered by filterbox or Pause chkbox change.
CallUpdateFilter:
GuiControl, Focus, %GUIEdithWnd% ;refocus filterbox always
GuiControlGet, Paused,, %GUIPausehWnd% ;get current Pause state
If (Paused == 1)
Return ;stop msging (ie live-flitering) while paused
GoSub, UpdateFilter ;else proceed with filter update
Return
;get filterbox content and pass to XY
UpdateFilter:
GuiControlGet, StrFilter,, %GUIEdithWnd% ;get current filterbox text
; escape and enclose in specified quotes
StrFilter := Quote . StrReplace(StrFilter, Quote, Quote . Quote) . Quote
;same filter twice resets VF, so skip that
If (LastFilter != StrFilter) { ;check if last sent filter is unique
LastFilter := StrFilter ;remember current filter as last one
StrFilter := "::filter " StrFilter ;make XY filtering script
MsgToXY(StrFilter) ;send filter msg
StrFilter := "" ;forget current filter
}
Return
;toggles pause status
lblTogglePause:
GuiControlGet, Paused,, %GUIPausehWnd% ;get current 'P'ause state
GuiControl,, %GUIPausehWnd%, % ((Paused == 0) ? 1 : 0) ;toggle status
;updateFilter is set to run automatically on pause state change
;but it doesn't seem to trigger on programmatic change
GoSub, CallUpdateFilter
Return
;handle escape routes
GuiClose:
GuiEscape:
ExitApp
Return
;focus parent XY window
lblFocusXY:
FocusXY()
Return
;focus own window
lblFocusGUI:
FocusGUI()
Return
;focus own window. also triggered on WM_Mouseover (else ctrl under GUI gets focus)
FocusGUI() {
global Showtip, Shortcut
IfWinActive, ahk_id %XYhWnd%
WinActivate, ahk_id %GUIEdithWnd% ;focus only if parent XY is active
;show a little tooltip
IfWinActive, ahk_id %GUIhWnd%
{
If (ShowTip != 1) { ;user disabled tips or not shown yet this session
ShowTip = 1 ;remember that tooltips have been shown once (now)
ToolTip ;hide existing tooltip
SetTimer, TTOn, 10 ;show tips after a slight delay
}
Return
TTOn: ;sub to show tips
ToolTip, % "CHECKBOX/Alt+P: Pause livemode`nTEXTBOX: enter filter pattern`n"
. "FOCUS HOTKEY:" . (Shortcut == "" ? "{None}": Shortcut)
SetTimer, TTOn, Off ;delete this timer so tips are shown once per session
SetTimer, TTOff, 2000 ;hide tip after a delay
Return
TTOff: ;sub to hide tips
ToolTip ;hide existing tips
SetTimer, TTOff, Off ;delete this timer
Return
}
Return
}
;focus parent XY window
FocusXY() {
IfWinActive, ahk_id %GUIhWnd%
WinActivate, ahk_id %XYhWnd%
Return
}
;triggered on WM_DESTROY
Destroyer() {
ExitApp
Return
}
ActionTrigger:
If (ActionData == "FOCUS")
FocusGUI()
Else If (ActionData == "QUIT")
ExitApp
Return
;=== MsgToXY() =================================================================
;send arg_Msg to %XYhWnd% via WM_COPYDATA
;function lifted from binocular222's XYplorer Messenger[AHK], (thanks!)
MsgToXY(arg_Msg) {
Size := StrLen(arg_Msg)
If !(A_IsUnicode)
VarSetCapacity(Data, Size*2,0),StrPut(arg_Msg,&Data,Size,"UTF-16")
Else
Data := arg_Msg
VarSetCapacity(COPYDATA,A_PtrSize*3,0),NumPut(dwDataMode[2],COPYDATA,0,"Ptr")
NumPut(Size*2,COPYDATA,A_PtrSize,"UInt"),NumPut(&Data,COPYDATA,A_PtrSize*2,"Ptr")
SendMessage,0x4A,0,©DATA,,ahk_id %XYhWnd%
Return
}
;=== End of MsgToXY() ==========================================================
;=== MsgFromXY() ===============================================================
;triggers on recv WM_COPYDATA from %XYhWnd%, puts data to %ReceivedData%
MsgFromXY(wParam, lParam) {
StringAddress := NumGet(lParam+2*A_PtrSize)
cbData := NumGet(lParam+A_PtrSize)/2,CopyOfData := StrGet(StringAddress)
dwData := NumGet(lParam+0) ; dwData is 1st DWORD sized member
;mode 0==4194304/1==4194305/2==4194306
If (dwData == dwDataMode[1]) ; mode 0, continue
StringLeft,ReceivedData,CopyOfData,cbData
Else { ;mode 1, trigger app action
StringLeft,ActionData,CopyOfData,cbData
Gosub, ActionTrigger
}
Return
}
;=== End of MsgFromXY() ========================================================
;=== GetFont() =================================================================
;returns font (and it's size) used in a ctrl with hwnd of arg_hWnd
;fontname = function return, and fontsize = A_LastError
;By SKAN www.autohotkey.com/forum/viewtopic.php?p=465438#465438
GetFont(arg_hwnd) {
SendMessage 0x31,0,0,,ahk_id %arg_hwnd%
IfEqual,ErrorLevel,FAIL,Return
hFont := Errorlevel,VarSetCapacity(LF,szLF := 60*(A_IsUnicode ? 2:1))
DllCall("GetObject","UInt",hFont,"Int",szLF,"UInt",&LF)
hDC := DllCall("GetDC","UInt",hwnd),DPI := DllCall("GetDeviceCaps","UInt",hDC,"Int",90)
DllCall("ReleaseDC","Int",0,"UInt",hDC),S := Round((-NumGet(LF,0,"Int")*72)/DPI)
Return DllCall("MulDiv","Int",&LF+28,"Int",1,"Int",1,"Str"),DllCall("SetLastError","UInt",S)
}
;=== End of GetFont() ==========================================================
;cleanup filter and perms on exit. Triggered on "normal" script/GUI exit
ExitRoutine:
GUI, Hide ;exiting "looks" slightly faster
SetTimer, UpdatePosAB, Off
SetTimer, UpdatePosWin, Off
If WinExist("ahk_id " . XYhWnd) {
WinActivate, ahk_id %XYhWnd% ;reactivate parent
If (SyncPos == 1) ;revert AB visibility to pre-exec
MsgToXY("::setlayout('showaddressbar=" ABState "');")
;make and send cleanup script
endMsg := "::filter;unset $p_XYAHKLiveFilter_A,$p_XYAHKLiveFilter_B;"
. ((OwnCTB >= 1) ? "ctbstate(0, " OwnCTB ");" : "")
MsgToXY(endMsg)
}
ExitApp
Return