-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathFileExplorerNotes.ahk
More file actions
497 lines (415 loc) · 17.2 KB
/
Copy pathFileExplorerNotes.ahk
File metadata and controls
497 lines (415 loc) · 17.2 KB
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
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
; ============================================================================
; PROJECT : FileExplorerNotes v2.0
; AUTHOR : Gued3s
; DESCRIPTION : "Commit messages" for your local files. Context-aware
; description system for Windows Explorer.
; ARCHITECTURE: AHK v2 Native GUI, Map-based Window Manager, Atomic I/O,
; Win11 Tabs COM Resilience, O(1) FIFO Cache.
; LICENSE : MIT
; ============================================================================
#Requires AutoHotkey v2.0
#SingleInstance Force
; ============================================================================
; 1. GLOBAL CONFIGURATION
; - Defines visual themes (Dark Mode) and cache limits.
; - Initializes the window registry to prevent duplicates.
; ============================================================================
; Dark Mode Colors (Win11 Native)
global COLOR_BG := "1E1E1E"
global COLOR_EDIT := "2D2D2D"
global COLOR_TEXT := "FFFFFF"
global COLOR_LINE := "000000"
global COLOR_BTN := "0066CC"
; Preview & Cache Management
global PreviewState := Map("Active", false, "LastPath", "")
global NoteCache := Map()
global CACHE_MAX_SIZE := 50
global CACHE_MAX_AGE := 30000
; GUI Windows Registry (prevent duplicates, memory leaks)
global OpenGuis := Map()
; Apply Dark Mode Globally
if (VerCompare(A_OSVersion, "10.0.18362") >= 0) {
try DllCall("uxtheme\135", "int", 2)
}
OnExit(ExitHandler)
ExitHandler(*) {
ToolTip()
; Clean up any remaining GUI windows
for filePath, guiObj in OpenGuis {
try guiObj.Destroy()
}
}
; ============================================================================
; 2. EXPLORER HOTKEYS (Context-Aware)
; - Restricts shortcuts to Windows Explorer windows only.
; - Prevents interference with other applications.
; ============================================================================
#HotIf WinActive("ahk_class CabinetWClass ahk_exe explorer.exe")
^+d:: CreateNote() ; Ctrl+Shift+D : Create/Edit Note
^q:: PreviewStart() ; Ctrl+Q (Hold) : Preview Note
^q Up:: PreviewStop() ; Ctrl+Q (Release) : Hide Preview
#HotIf
; ============================================================================
; 3. CORE: CREATE NOTE LOGIC
; - Identifies selected files and resolves system paths.
; - Manages the hidden ".filenotes" directory structure.
; ============================================================================
CreateNote() {
shellWin := GetExplorerWindow()
if !shellWin {
MsgBox("Explorer window not found.", "Error", "Icon!")
return
}
targetPath := ""
try {
for item in shellWin.Document.SelectedItems {
targetPath := item.Path
break
}
}
; Validation: File must exist and not be a note itself
if !targetPath || !FileExist(targetPath) || InStr(targetPath, "\.filenotes\") {
ToolTip("⚠ Please select a valid file.")
SetTimer(() => ToolTip(), -1500)
return
}
; Extract filename WITH extension (important!)
SplitPath(targetPath, &fileName, &fileDir)
metaDir := fileDir "\.filenotes"
notePath := metaDir "\" fileName ".txt"
; Create .filenotes directory if needed
if !DirExist(metaDir) {
try {
DirCreate(metaDir)
FileSetAttrib("+H", metaDir)
} catch as err {
MsgBox("Cannot create notes directory:`n" err.Message, "Error", "Icon!")
return
}
}
; Open in GUI (prevent duplicate windows)
if OpenGuis.Has(notePath) {
try {
WinActivate("ahk_id " OpenGuis[notePath].Hwnd)
return
} catch {
OpenGuis.Delete(notePath)
}
}
OpenNoteGUI(notePath, fileName)
}
; ============================================================================
; 4. NATIVE GUI EDITOR
; - Custom Dark Mode text editor with Dirty Check monitoring.
; - Responsive layout that adapts to window resizing.
; - I still haven't managed to make the buttons look nice without the white border around them, but what matters is that it works
; ============================================================================
OpenNoteGUI(notePath, displayName) {
; Load existing content or start empty
initialContent := ""
if FileExist(notePath) {
try initialContent := FileRead(notePath, "UTF-8")
}
; Create window with dark theme support
noteGui := Gui("+Resize +MinSize400x300 +OwnDialogs", "Note: " displayName)
noteGui.MarginX := 0
noteGui.MarginY := 0
noteGui.BackColor := COLOR_BG
noteGui.IsDirty := false
noteGui.NotePath := notePath
; Win11 Dark Title Bar
try DllCall("dwmapi\DwmSetWindowAttribute", "ptr", noteGui.Hwnd, "int", 20, "int*", 1, "int", 4)
try DllCall("dwmapi\DwmSetWindowAttribute", "ptr", noteGui.Hwnd, "int", 35, "int*", 0x00000000, "int", 4)
noteGui.SetFont("s10 c" COLOR_TEXT, "Segoe UI")
; --- EDIT CONTROL ---
editCtrl := noteGui.Add("Edit", "vEditCtrl x0 y0 w600 r20 -E0x200 -Border +Wrap +VScroll +WantReturn Background" COLOR_EDIT " c" COLOR_TEXT, initialContent)
try DllCall("uxtheme\SetWindowTheme", "ptr", editCtrl.Hwnd, "str", "DarkMode_CFD", "ptr", 0)
SendMessage(0x00D3, 3, (10 << 16) | 10, editCtrl.Hwnd) ; 10px margins
; Track modifications
editCtrl.OnEvent("Change", GuiChange.Bind(noteGui))
; --- SEPARATOR LINE ---
noteGui.Add("Text", "vSeparator x0 y0 w0 h1 Background" COLOR_LINE)
; --- BUTTONS ---
btnSave := noteGui.Add("Button", "vBtnSave w100 h30 Default", "Save")
btnCancel := noteGui.Add("Button", "vBtnCancel x+10 w100 h30", "Cancel")
; Aplica o tema escuro nativo do Windows 11 (Deixa cinza e arredondado)
try DllCall("uxtheme\SetWindowTheme", "ptr", btnSave.Hwnd, "str", "DarkMode_Explorer", "ptr", 0)
try DllCall("uxtheme\SetWindowTheme", "ptr", btnCancel.Hwnd, "str", "DarkMode_Explorer", "ptr", 0)
; --- EVENTS ---
btnSave.OnEvent("Click", GuiSave.Bind(noteGui, notePath, editCtrl))
btnCancel.OnEvent("Click", GuiClose.Bind(noteGui, notePath, editCtrl))
noteGui.OnEvent("Close", GuiClose.Bind(noteGui, notePath, editCtrl))
noteGui.OnEvent("Size", GuiResize)
; --- LOCAL HOTKEY: Ctrl+S ---
HotIfWinActive("ahk_id " noteGui.Hwnd)
Hotkey("^s", GuiSave.Bind(noteGui, notePath, editCtrl))
HotIf()
; Track window globally
OpenGuis[notePath] := noteGui
noteGui.Show("w600 h400")
editCtrl.Focus()
}
; --- Event Handlers ---
GuiChange(noteGui, GuiCtrlObj, Info) {
noteGui.IsDirty := true
}
GuiResize(GuiObj, MinMax, Width, Height) {
; Ignore minimize events
if (MinMax = -1)
return
try {
; Edit Control: from top (0) to 60px before bottom
GuiObj["EditCtrl"].Move(0, 0, Width, Height - 60)
; Separator Line: 1px height, positioned at Height - 60
GuiObj["Separator"].Move(0, Height - 60, Width, 1)
; Save Button: bottom-left area with 15px padding
GuiObj["BtnSave"].Move(15, Height - 45, 100, 30)
; Cancel Button: next to Save button with 10px gap
GuiObj["BtnCancel"].Move(125, Height - 45, 100, 30)
} catch {
; Graceful failure
}
}
GuiSave(noteGui, notePath, editCtrl, *) {
SaveNoteAtomic(notePath, editCtrl.Value)
noteGui.IsDirty := false
GuiDestroy(noteGui, notePath)
}
GuiClose(noteGui, notePath, editCtrl, *) {
; Check for unsaved changes
if noteGui.IsDirty {
result := MsgBox("You have unsaved changes. Save before closing?", "Unsaved Changes", "YesNoCancel Icon?")
if result = "Cancel"
return ; Corrigido: Em AHK v2, apenas 'return' sem destruir a janela já previne o fechamento aqui
if result = "Yes"
SaveNoteAtomic(notePath, editCtrl.Value)
}
GuiDestroy(noteGui, notePath)
}
GuiDestroy(noteGui, notePath) {
try {
HotIfWinActive("ahk_id " noteGui.Hwnd)
Hotkey("^s", "Off")
HotIf()
}
OpenGuis.Delete(notePath)
noteGui.Destroy()
}
; ============================================================================
; 5. ATOMIC SAVE (Data Integrity)
; - Strategy: Write to .tmp -> Verify -> Replace original.
; - Prevents file corruption during crashes or power loss.
; ============================================================================
SaveNoteAtomic(notePath, content) {
tmpPath := notePath ".tmp"
try {
; Write to temporary file first
f := FileOpen(tmpPath, "w", "UTF-8-RAW")
if !f {
throw Error("Cannot open file for writing")
}
f.Write(content)
f.Close()
; Atomic replacement (overwrite = 1)
FileMove(tmpPath, notePath, 1)
; Invalidate cache
if NoteCache.Has(notePath)
NoteCache.Delete(notePath)
} catch as err {
try FileDelete(tmpPath)
MsgBox("Error saving note:`n" err.Message, "Error", "Icon!")
}
}
; ============================================================================
; 6. PREVIEW SYSTEM (ctrl + q / Hold to View)
; - High-performance polling system with O(1) FIFO Cache.
; - Minimizes Disk I/O and CPU usage during navigation.
; ============================================================================
ClearPreview() => ToolTip()
PreviewStart() {
global PreviewState
SetTimer(ClearPreview, 0)
if PreviewState["Active"]
return
PreviewState["Active"] := true
SetTimer(PreviewTick, 100)
PreviewTick()
}
PreviewStop() {
global PreviewState
PreviewState["Active"] := false
PreviewState["LastPath"] := ""
SetTimer(PreviewTick, 0)
SetTimer(ClearPreview, -250) ; 1 sec delay to clear the tooltip
}
PreviewTick() {
global PreviewState, NoteCache
; Guard: prevent re-entrancy
static _inProgress := false
if _inProgress
return
_inProgress := true
try {
if !PreviewState["Active"] || !WinActive("ahk_class CabinetWClass ahk_exe explorer.exe") {
if PreviewState["Active"]
PreviewStop()
return
}
shellWin := GetExplorerWindow()
if !shellWin {
ToolTip()
return
}
focusedPath := ""
try {
focusedItem := shellWin.Document.FocusedItem
if focusedItem
focusedPath := focusedItem.Path
}
if !focusedPath || InStr(focusedPath, "\.filenotes\") {
ToolTip()
return
}
SplitPath(focusedPath, &fileName, &fileDir)
notePath := fileDir "\.filenotes\" fileName ".txt"
if notePath = PreviewState["LastPath"]
return
PreviewState["LastPath"] := notePath
if FileExist(notePath) {
contentToDisplay := ""
currentFileTime := ""
try currentFileTime := FileGetTime(notePath, "M")
; CACHE LOOKUP
if NoteCache.Has(notePath) {
cachedData := NoteCache[notePath]
if currentFileTime = cachedData.FileTime && (A_TickCount - cachedData.AccessTime) < CACHE_MAX_AGE {
contentToDisplay := cachedData.Content
cachedData.AccessTime := A_TickCount
} else {
NoteCache.Delete(notePath)
}
}
; DISK READ
if !contentToDisplay {
try {
contentToDisplay := FileRead(notePath, "m4000 UTF-8")
if contentToDisplay {
NoteCache[notePath] := {
Content: contentToDisplay,
AccessTime: A_TickCount,
FileTime: currentFileTime
}
; Simple FIFO eviction
if NoteCache.Count > CACHE_MAX_SIZE {
for key in NoteCache {
NoteCache.Delete(key)
break
}
}
}
}
}
ToolTip(contentToDisplay ? contentToDisplay : "(Empty description)")
} else {
ToolTip("(No description)")
}
} finally {
_inProgress := false
}
}
; ============================================================================
; 7. EXPLORER DETECTION (WIN11 TABS SUPPORT)
; - Advanced COM logic to identify the physically active tab.
; - Ensures 100% accuracy in multi-tab Explorer environments.
; ============================================================================
GetExplorerWindow() {
hwnd := WinExist("A")
if !hwnd
return 0
; Detect active tab handle (Win11)
activeTab := 0
try activeTab := ControlGetHwnd("ShellTabWindowClass1", "ahk_id " hwnd)
try {
shell := ComObject("Shell.Application")
for window in shell.Windows {
if window.Hwnd != hwnd
continue
; If window has tabs, verify this is the active one
if activeTab {
static IID_IShellBrowser := "{000214E2-0000-0000-C000-000000000046}"
try {
shellBrowser := ComObjQuery(window, IID_IShellBrowser, IID_IShellBrowser)
ComCall(3, shellBrowser, "uint*", &thisTab := 0)
if thisTab != activeTab
continue
} catch {
continue
}
}
; Verify document accessibility
try {
_ := window.Document.Folder.Self.Path
} catch {
continue
}
return window
}
} catch {
return 0
}
return 0
}
; ============================================================================
; 📂 USER GUIDE & REFERENCE
; ============================================================================
/*
========================================================================
QUICK START
========================================================================
1. Select any file or folder in Windows Explorer.
2. Press Ctrl+Shift+D to open the our notepad.
3. Type your context/note and click 'Save' (or press Ctrl+S).
4. Click and hold ctrl q to see a quick preview of your note in a tooltip.
========================================================================
DEFAULT HOTKEYS
========================================================================
• Ctrl + Shift + D : Create or Edit a note.
• ctrl+q (Hold) : Preview note content.
• Ctrl + S : Save note (while editor is open).
• Esc : Close editor / Cancel changes.
========================================================================
STORAGE SYSTEM (Sidecar Files)
========================================================================
Notes are stored in a hidden subfolder named ".filenotes".
• Original File: C:\MyFolder\Project_Data.xlsx
• Context Note: C:\MyFolder\.filenotes\Project_Data.xlsx.txt
========================================================================
TECHNICAL HIGHLIGHTS
========================================================================
• Win11 Tabs: Active tab detection via IShellBrowser COM.
• Atomic Save: .tmp file strategy for zero data loss.
• Dirty Check: Prevents closing with unsaved changes.
• FIFO Cache: 30s TTL to save system resources.
========================================================================
CUSTOMIZATION
========================================================================
• Colors: Search for COLOR_ variables in Section 1.
• Cache: Search for CACHE_ variables in Section 1.
• Keys: Modify trigger combinations in Section 2.
========================================================================
HOTKEY SYNTAX GUIDE
========================================================================
^ = Ctrl | ! = Alt | + = Shift | # = Windows Key
Example: "^+d" means Ctrl+Shift+D
========================================================================
CONFLICTS TO AVOID IN EXPLORER
========================================================================
- Ctrl+Shift+N (New Folder) | - F2 (Rename)
- Alt+Enter (Properties) | - Ctrl+W (Close Window)
========================================================================
For more details on Hotkey syntax, visit:
https://www.autohotkey.com/docs/v2/Hotkeys.htm
*/
; ============================================================================
; END OF SCRIPT
; ============================================================================